Tôi chỉ định mã hóa một số giá trị ở đây để khớp với chỉ mục mảng "đầu tiên" của "polaire"
và chỉ mục mảng "thứ hai" của "matrice"
để trình diễn. Lưu ý ở đây cách sử dụng $elemMatch
trong $match
giai đoạn đường ống tổng hợp và việc sử dụng $map
và $filter
trong $project
giai đoạn đường ống:
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")
);
Điều này dịch sang số tuần tự này:
[
{ "$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 ] }
]
}
}
}
}
}
}
}}
]
Và tạo ra đầu ra tài liệu phù hợp dưới dạng:
{
"_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
]
}
]
}
]
}
Phần "truy vấn" của $match
điều quan trọng là thực sự chọn "(các) tài liệu" đáp ứng các điều kiện. Không sử dụng $elemMatch
biểu thức thực sự có thể khớp với các tài liệu mà không có điều kiện chính xác trên cùng các phần tử bên trong và trên thực tế sẽ được trải rộng trên tất cả các phần tử mảng có trong (các) tài liệu.
Lọc mảng được lồng vào nhau trước tiên sử dụng $map
vì phần tử mảng "bên trong" cũng sẽ phải chịu "bộ lọc" của chính nó. Vì vậy, cả "input"
nguồn cho $map
cũng như "đầu ra" là "in"
tham chiếu đến $filter
điều kiện để khớp với (các) phần tử cụ thể của mảng.
Là "điều kiện" ("cond"
) thành $filter
chúng tôi sử dụng "biểu thức tổng hợp logic" như boolean $and
cũng như các "toán tử so sánh" khác để bắt chước các điều kiện tương tự của các đối tác "toán tử truy vấn" của chúng. Những điều này chịu trách nhiệm về logic khớp với các mục mảng chính xác để trả về trong kết quả "đã lọc".
Để tham khảo, đây là dữ liệu nguồn mà từ đó kết quả thu được phải giống như được đăng trong câu hỏi:
{
"_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
]
}
]
}
]
}