Spring 数据匹配和过滤嵌套数组 [英] Spring data Match and Filter Nested Array
问题描述
如何从嵌套数组中提取数据?
How can extract data from nested array ?
我想提取数组项values",其中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"
的first"数组索引和second"" "matrice"
的数组索引用于演示.注意这里 $elemMatch
的用法在 $match
聚合管道阶段以及 $map
的用法和$filter
在 $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
因为内部"数组元素也将受到它自己的过滤".所以的
以及作为 "input"
源>$map"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.
作为条件"( "cond"
)到 $filter
我们使用逻辑聚合表达式",例如布尔值 $and
以及其他 "comparison operators" 来模仿他们的查询运算符"对应项的相同条件.这些负责匹配正确数组项以在过滤"结果中返回的逻辑.
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 数据匹配和过滤嵌套数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!