Ето как MongoDB обработва основната проекция с елементи от масив. Въпреки че можете да направите нещо подобно:
Model.findOne({}, { "comments.upvotes": 1 },function(err,doc) {
})
И това просто ще върне полето „за гласуване“ от поддокументите на масива от коментари за всички документи, отговарящи на условието и всички елементи на масива, разбира се, не можете да комбинирате това с избрана позиционна проекция, като използвате позиционен $
оператор. Това основно произтича от "теорията" че като цяло всъщност искате да върнете целия масив. Ето как винаги е работило и няма вероятност скоро да се промени.
За да получите това, което искате, имате нужда от разширените възможности за манипулиране на документи, предлагани от рамка за агрегиране . Това ви дава повече контрол върху начина на връщане на документите:
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) {
}
);
Или в съвременните версии на MongoDB след 2.6 можете дори да направите това:
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) {
}
)
И това използва $map
и $setDifference
оператори за извършване на "вградено" филтриране на съдържанието на масива, без първо да се обработва $unwind
етап.
Така че, ако искате повече контрол върху това как се връща документът, тогава рамката за агрегиране е начинът да го направите, когато работите с вградени документи.