ネストされた配列からデータを抽出するにはどうすればよいですか?
Wind_speedパラメーター値がvitRange.minとvitRange.maxの間にある配列アイテム「values」を抽出したい(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);
2番目のアプローチ:
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);
最後のアプローチ:(cf。 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"
_の「2番目の」配列インデックスに一致するようにいくつかの値をハードコーディングします。ここで、 _$elemMatch
_ 集約パイプラインステージでの _$match
_ の使用法と _$map
_ および _$filter
_ in _$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
_ を使用しない場合、式は同じ内部要素に正しい条件がなくても実際にドキュメントに一致する可能性があり、実際にはドキュメントに存在するすべての配列要素に分散されます。 (s)。
最初にネストされた配列のフィルタリングでは、 _$map
_ を使用します。これは、「内部」配列要素も独自の「フィルタリング」の対象となるためです。したがって、 _"input"
_ の_$map
_ソースと_"in"
_としての「出力」の両方が _$filter
_ 配列の特定の要素に一致させるための条件。
「条件」(_"cond"
_)から _$filter
_ として、ブール などの「論理集計式」を使用します。 _$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
]
}
]
}
]
}
_