W ten sposób MongoDB obsługuje podstawową projekcję z elementami tablicy. Chociaż możesz zrobić coś takiego:
Model.findOne({}, { "comments.upvotes": 1 },function(err,doc) {
})
A to po prostu zwróciłoby pole „upvotes” z poddokumentów tablicy komentarzy dla wszystkich dokumentów spełniających warunek i wszystkich elementów tablicy, oczywiście nie można połączyć tego z wybraną projekcją pozycyjną za pomocą pozycyjny $
operator. Wynika to zasadniczo z "teorii" że ogólnie faktycznie chcesz zwrócić całą tablicę. Tak to zawsze działało i prawdopodobnie wkrótce się nie zmieni.
Aby uzyskać to, czego chcesz, potrzebujesz rozszerzonych możliwości manipulacji dokumentami oferowanych przez struktura agregacji . Daje to większą kontrolę nad sposobem zwracania dokumentów:
Model.aggregate(
[
// Match the document containing the array element
{ "$match": { "comments._id" : oid } },
// Unwind to "de-normalize" the array content
{ "$unwind": "$comments" },
// Match the specific array element
{ "$match": { "comments._id" : oid } },
// Group back and just return the "upvotes" field
{ "$group": {
"_id": "$_id",
"comments": { "$push": { "upvotes": "$comments.upvotes" } }
}}
],
function(err,docs) {
}
);
Lub w nowoczesnych wersjach MongoDB od 2.6 możesz nawet to zrobić:
Model.aggregate(
[
{ "$match": { "comments._id" : oid } },
{ "$project": {
"comments": {
"$setDifference": [
{ "$map": {
"input": "$comments",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el._id", oid ] },
{ "upvotes": "$$el.upvotes" },
false
]
}
}},
[false]
]
}}
}}
],
function(err,docs) {
}
)
I to używa $map
i $setDifference
operatorów do filtrowania zawartości tablicy bez uprzedniego przetwarzania $unwind
scena.
Jeśli więc chcesz mieć większą kontrolę nad sposobem zwracania dokumentu, podczas pracy z osadzonymi dokumentami najlepszym rozwiązaniem jest struktura agregacji.