Så här hanterar MongoDB grundläggande projektion med arrayelement. Medan du kan göra något så här:
Model.findOne({}, { "comments.upvotes": 1 },function(err,doc) {
})
Och det skulle bara returnera "upvotes"-fältet från underdokumenten i kommentarsfältet för alla dokument som matchar villkoret och alla arrayelement, naturligtvis, du kan inte kombinera detta med en vald positionsprojektion med positional $
operatör. Detta härrör i grunden från "teorin" det allmänt du vill faktiskt returnera hela arrayen. Så det är så det alltid har fungerat och kommer sannolikt inte att förändras snart.
För att få det du vill behöver du de utökade funktionerna för dokumentmanipulering som erbjuds av aggregationsramverk . Detta ger dig mer kontroll över hur dokumenten returneras:
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) {
}
);
Eller i moderna versioner av MongoDB sedan 2.6 kan du till och med göra detta:
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) {
}
)
Och som använder $map
och $setDifference
operatörer att göra en "in-line"-filtrering av arrayinnehållet utan att först bearbeta en $unwind
skede.
Så om du vill ha mer kontroll över hur dokumentet returneras, så är aggregeringsramverket sättet att göra det när du arbetar med inbäddade dokument.