如何从嵌套数组中提取数据?
我想提取其中wind_speed参数值在vitRange.min和vitRange.max之间的数组项“值”(twaRange和风向的条件相同)
资料:
{ "name" : "race" ,"polaire" : [ { "voile" : "foc" , "matrice" :[ { "vitRange" : { "min" : 0, "max" : 4} ,"twaRange" : { "min" : 0, "max" : 30} ,"values" : [0, 0, 0, 2.4] }, { "vitRange" : { "min" : 4, "max" : 6} ,"twaRange" : { "min" : 30, "max" : 33} ,"values" : [0, 0, 2.4, 3.7] } ] }, { "voile" : "spi" , "matrice" :[ { "vitRange" : { "min" : 0, "max" : 4} ,"twaRange" : { "min" : 0, "max" : 30} ,"values" : [0, 0, 0, 1.4] }, { "vitRange" : { "min" : 4, "max" : 6} ,"twaRange" : { "min" : 30, "max" : 33} ,"values" : [0, 0, 1.4, 2.2] } ] } ] }
第一种方法:
Query query = new Query( Criteria.where("name").is(name) .andOperator( Criteria.where("polaire.voile").is(sail), Criteria.where("polaire.matrice.twaRange.max").lt(wind_direction), Criteria.where("polaire.matrice.twaRange.min").gte(wind_direction), Criteria.where("polaire.matrice.vitRange.max").lt(wind_speed), Criteria.where("polaire.matrice.vitRange.min").gte(wind_speed) ) ); query.fields().include("polaire.matrice.values"); Polaires data = mongoTemplate.findOne(query, Polaires.class);
第二种方法:
Criteria findPolaireCriteria = Criteria.where("name").is(name); Criteria findValueCriteria = Criteria.where("polaire").elemMatch(Criteria.where("voile").is(sail)) .andOperator( Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("max").lt(wind_direction)), Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("min").gte(wind_direction)), Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("max").lt(wind_speed)), Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("min").gte(wind_speed))); BasicQuery query = new BasicQuery(findPolaireCriteria.getCriteriaObject(), findValueCriteria.getCriteriaObject()); query.fields().include("polaire.matrice.values"); Polaires data = mongoTemplate.findOne(query, Polaires.class);
最后一种方法:(请参见查询文档及其与mongodb中条件匹配的所有子文档(使用spring))
Aggregation aggregation = newAggregation( match(Criteria.where("name").is(name) .and("polaire").elemMatch(Criteria.where("voile").is(sail))), project( "_id", "matrice") .and(new AggregationExpression() { @Override public DBObject toDbObject(AggregationOperationContext aggregationOperationContext ) { DBObject filter = new BasicDBObject("input", "$matrice") .append("as", "result") .append("cond", new BasicDBObject("$and", Arrays.<Object> asList( new BasicDBObject("$gte", Arrays.<Object> asList("$$result.vitRange.min", 0)), new BasicDBObject("$lt", Arrays.<Object> asList("$$result.vitRange.max", 4)) ) ) ); return new BasicDBObject("$filter", filter); } }).as("matrice") ); List<BasicDBObject> dbObjects = mongoTemplate.aggregate(aggregation, "collectionname", BasicDBObject.class).getMappedResults();
或另一个…
List<AggregationOperation> list = new ArrayList<AggregationOperation>(); list.add(Aggregation.match(Criteria.where("name").is(name))); list.add(Aggregation.unwind("polaire")); list.add(Aggregation.match(Criteria.where("polaire.voile").is(sail))); list.add(Aggregation.unwind("polaire.matrice")); list.add(Aggregation.match(Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("max").lt(wind_direction)))); list.add(Aggregation.match(Criteria.where("polaire.matrice.twaRange").elemMatch(Criteria.where("min").gte(wind_direction)))); list.add(Aggregation.match(Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("max").lt(wind_speed)))); list.add(Aggregation.match(Criteria.where("polaire.matrice.vitRange").elemMatch(Criteria.where("min").gte(wind_speed)))); list.add(Aggregation.group("id", "polaire.matrice").push("polaire.matrice.values").as("values")); list.add(Aggregation.project("polaire.matrice","values")); TypedAggregation<Polaires> agg = Aggregation.newAggregation(Polaires.class, list); List<BasicDBObject> dbObjects = mongoTemplate.aggregate(agg, "collectionname", BasicDBObject.class).getMappedResults();
在论坛上一次又一次地转过身,但是他们都没有帮助我。问题可能是在处理json结构(使其易于请求)方面?
谢谢
我将在此处硬编码一些值以匹配的“第一个”数组索引"polaire"和“第二个”数组索引"matrice"进行演示。请注意此处$elemMatch在$match聚合管道阶段的用法$map以及$filter在管道阶段的和的用法$project:
"polaire"
"matrice"
$elemMatch
$match
$map
$filter
$project
Aggregation aggregation = newAggregation( match( Criteria.where("name").is("race").and("polaire").elemMatch( Criteria.where("voile").is("foc") .and("matrice").elemMatch( Criteria.where("vitRange.min").lt(5) .and("vitRange.max").gt(5) .and("twaRange.min").lt(32) .and("twaRange.max").gt(32) ) ) ), project("name") .and(new AggregationExpression() { @Override public DBObject toDbObject(AggregationOperationContext context) { return new BasicDBObject("$map", new BasicDBObject("input",new BasicDBObject( "$filter", new BasicDBObject( "input", "$polaire") .append("as","p") .append("cond", new BasicDBObject("$eq", Arrays.asList("$$p.voile","foc"))) )) .append("as","p") .append("in", new BasicDBObject( "voile", "$$p.voile") .append("matrice",new BasicDBObject( "$filter", new BasicDBObject( "input", "$$p.matrice") .append("as","m") .append("cond", new BasicDBObject( "$and", Arrays.asList( new BasicDBObject("$lt", Arrays.asList("$$m.vitRange.min", 5)), new BasicDBObject("$gt", Arrays.asList("$$m.vitRange.max", 5)), new BasicDBObject("$lt", Arrays.asList("$$m.twaRange.min", 32)), new BasicDBObject("$gt", Arrays.asList("$$m.twaRange.max", 32)) ) )) )) ) ); } }).as("polaire") );
转化为以下序列化:
[ { "$match": { "name": "race", "polaire": { "$elemMatch": { "voile": "foc", "matrice": { "$elemMatch": { "vitRange.min": { "$lt": 5 }, "vitRange.max": { "$gt": 5 }, "twaRange.min": { "$lt": 32 }, "twaRange.max": { "$gt": 32 } } } } } }}, { "$project": { "name": 1, "polaire": { "$map": { "input": { "$filter": { "input": "$polaire", "as": "p", "cond": { "$eq": [ "$$p.voile", "foc" ] } } }, "as": "p", "in": { "voile": "$$p.voile", "matrice": { "$filter": { "input": "$$p.matrice", "as": "m", "cond": { "$and": [ { "$lt": [ "$$m.vitRange.min", 5 ] }, { "$gt": [ "$$m.vitRange.max", 5 ] }, { "$lt": [ "$$m.twaRange.min", 32 ] }, { "$gt": [ "$$m.twaRange.max", 32 ] } ] } } } } } } }} ]
并产生匹配的文档输出为:
{ "_id" : ObjectId("593bc2f15924d4206cc6e399"), "name" : "race", "polaire" : [ { "voile" : "foc", "matrice" : [ { "vitRange" : { "min" : 4, "max" : 6 }, "twaRange" : { "min" : 30, "max" : 33 }, "values" : [ 0, 0, 2.4, 3.7 ] } ] } ] }
的“查询”部分$match对于实际选择符合条件的“文档”很重要。如果不使用$elemMatch该表达式,则实际上可以在相同内部元素上没有正确条件的情况下匹配文档,并且实际上会散布在文档中存在的所有数组元素中。
首先使用嵌套过滤数组,$map因为“内部”数组元素也将接受其自身的“过滤”。因此,"input"源$map和“输出” "in"都引用$filter条件以匹配数组的特定元素。
"input"
"in"
作为“条件”("cond"),$filter我们利用布尔值$and以及其他“比较运算符 ”之类的“逻辑聚合表达式”来模拟其与“查询运算符”对应物相同的条件。这些负责匹配正确数组项以返回“过滤”结果的逻辑。
"cond"
$and
作为参考,这是从中获取结果的源数据,该源数据应与问题中发布的源数据相同:
{ "_id" : ObjectId("593bc2f15924d4206cc6e399"), "name" : "race", "polaire" : [ { "voile" : "foc", "matrice" : [ { "vitRange" : { "min" : 0, "max" : 4 }, "twaRange" : { "min" : 0, "max" : 30 }, "values" : [ 0, 0, 0, 2.4 ] }, { "vitRange" : { "min" : 4, "max" : 6 }, "twaRange" : { "min" : 30, "max" : 33 }, "values" : [ 0, 0, 2.4, 3.7 ] } ] }, { "voile" : "spi", "matrice" : [ { "vitRange" : { "min" : 0, "max" : 4 }, "twaRange" : { "min" : 0, "max" : 30 }, "values" : [ 0, 0, 0, 1.4 ] }, { "vitRange" : { "min" : 4, "max" : 6 }, "twaRange" : { "min" : 30, "max" : 33 }, "values" : [ 0, 0, 1.4, 2.2 ] } ] } ] }