Dit is hoe MongoDB omgaat met basisprojectie met array-elementen. Terwijl je zoiets als dit kunt doen:
Model.findOne({}, { "comments.upvotes": 1 },function(err,doc) {
})
En dat zou gewoon het veld "upvotes" retourneren vanuit de subdocumenten van de array met opmerkingen voor alle documenten die overeenkomen met de voorwaarde en alle array-elementen natuurlijk, je kunt dit natuurlijk niet combineren met een geselecteerde positionele projectie met behulp van de positionele $
exploitant. Dit komt in feite voort uit de "theorie" dat in het algemeen je wilt eigenlijk de hele array retourneren. Dit is dus hoe het altijd heeft gewerkt en waarschijnlijk niet snel zal veranderen.
Om te krijgen wat je wilt, heb je de uitgebreide mogelijkheden voor documentmanipulatie nodig die worden aangeboden door de aggregatieraamwerk . Dit geeft u meer controle over hoe de documenten worden geretourneerd:
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) {
}
);
Of in moderne versies van MongoDB sinds 2.6 kun je dit zelfs doen:
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) {
}
)
En dat gebruikt de $map
en $setDifference
operators om een "in-line" filtering van de array-inhoud uit te voeren zonder eerst een $unwind
podium.
Dus als u meer controle wilt over hoe het document wordt geretourneerd, dan is het aggregatieraamwerk de manier om dit te doen bij het werken met ingesloten documenten.