问题描述
如何从嵌套数组中提取数据?
How can extract data from nested array ?
我想提取其中wind_speed参数值在vitRange.min和vitRange.max(twaRange和风向相同的条件)之间的数组项值"
I want to extract the array item "values" where wind_speed parameter value is between vitRange.min and vitRange.max (same condition for twaRange and wind direction)
数据:
{
"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))
Last approach:(cf. Query a document and all of its subdocuments that match a condition in mongodb (using 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结构上(使其易于请求)?
Turn around again and again on the forum but none of them help me.The issue is probably on working to the json structure (adapt it to easily request) ?
谢谢
推荐答案
我将在此处硬编码一些值,以匹配"polaire"
的第一"数组索引和"matrice"
的第二"数组索引进行示范.请注意此处 $elemMatch
的用法"https://docs.mongodb.com/manual/reference/operator/aggregation/match/" rel ="noreferrer"> $match
聚合管道阶段和 $map
和 $filter
="noreferrer"> $project
管道阶段:
I'm just going to hardcode some values here to match the "first" array index of "polaire"
and the "second" array index of "matrice"
for demonstration. Note here the usage of $elemMatch
in the $match
aggregation pipeline stage and the usage of $map
and $filter
in the $project
pipeline stage:
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 ] }
]
}
}
}
}
}
}
}}
]
并生成匹配的文档输出为:
And produces the matched document output as:
{
"_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
的情况下,表达式实际上可以匹配文档而无需在相同内部元素上的正确条件,实际上会分布在文档中存在的所有数组元素上.
The "query" portion of $match
is important to actually select the "document(s)" that meet the conditions. Without the usage of $elemMatch
the expression can actually match documents without the correct conditions on the same inner elements and in fact would be spread across all array elements present in the document(s).
首先使用 $map
过滤嵌套的数组因为内部"数组元素也将接受其自身的过滤".因此, $map
的"input"
源作为"in"
的输出",请引用 $filter
条件,以匹配数组的特定元素.
Filtering the array which is nested first uses $map
since the "inner" array element is also going to be subject to its own "filtering". So both the "input"
source for the $map
as well as the "output" as "in"
make reference to $filter
conditions in order to match the specific element(s) of the arrays.
作为 $filter
我们使用逻辑聚合表达式",例如布尔 以及其他比较运算符" 模仿与查询运算符"对应的条件相同的条件.这些负责匹配正确数组项以返回已过滤"结果的逻辑.
As the "conditions" ( "cond"
) to $filter
we make use of "logical aggregation expressions" such as the boolean $and
as well as the other "comparison operators" to mimic the same conditions of their "query operator" counterparts. These are responsible for the logic that matches the correct array items to return in the "filtered" result.
作为参考,这是从中获取结果的源数据,应与问题中发布的源数据相同:
For reference this is the source data from which the results are obtained which should be the same as posted in the question:
{
"_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
]
}
]
}
]
}
这篇关于Spring数据匹配和过滤嵌套数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!