Istnieje szczególna sztuczka, jak to zrobić, ale po pierwsze, jeśli masz dostępną MongoDB w wersji 2.6 lub nowszej, możesz robić, co chcesz, bez użycia $unwind
. Może to być bardzo przydatne w przypadku przetwarzania dużej liczby dokumentów.
Kluczowymi operatorami są tutaj $map
który przetwarza tablice w miejscu i $allElementsTrue
operator, który oceni twoje pola "wynikowe". Użycie tutaj "mapy" pozwala zarówno na testowanie wewnętrznej tablicy "testy", aby zobaczyć, gdzie wszystkie pola "wyniku" spełniają prawdziwy warunek. W przypadku tablicy zewnętrznej ten „wynik” można umieścić w tych dokumentach zgodnie z potrzebami, a pełna ocena dokumentu podlega tym samym zasadom:
db.test.aggregate([
{ "$project": {
"name": 1,
"result": {
"$allElementsTrue": {
"$map": {
"input": "$acts",
"as": "act",
"in": {
"$allElementsTrue": {
"$map": {
"input": "$$act.tests",
"as": "test",
"in": "$$test.result"
}
}
}
}
}
},
"acts": {
"$map": {
"input": "$acts",
"as": "act",
"in": {
"name": "$$act.name",
"result": {
"$allElementsTrue": {
"$map": {
"input": "$$act.tests",
"as": "test",
"in": "$$test.result"
}
}
},
"tests": "$$act.tests"
}
}
}
}}
])
Sposób wykonania tego we wcześniejszych wersjach wymaga $grupa
z powrotem w dwóch krokach, aby „odbudować” tablice podczas ponownego wykonywania testów na tych polach „wyniku”. Inną różnicą jest również użycie $min
operator jako false
będzie uważana za mniejszą wartość niż true
i ocenia zgodnie z tą samą koncepcją „allElements”:
db.test.aggregate([
{ "$unwind": "$acts" },
{ "$unwind": "$acts.tests" },
{ "$group": {
"_id": {
"_id": "$_id",
"name": "$name",
"actName": "$acts.name"
},
"result": { "$min": "$acts.tests.result" },
"tests": {
"$push": {
"name": "$acts.tests.name",
"result": "$acts.tests.result"
}
}
}},
{ "$group": {
"_id": "$_id._id",
"name": { "$first": "$_id.name" },
"result": { "$min": "$result" },
"acts": {
"$push": {
"name": "$_id.actName",
"result": "$result",
"tests": "$tests"
}
}
}}
])