V podstatě chcete $elemMatch
a $exists
operátor, protože to zkontroluje každý prvek a zjistí, zda podmínka "pole neexistuje" platí pro jakýkoli prvek:
Model.find({
"line_items": {
"$elemMatch": { "review_request_sent": { "$exists": false } }
}
},function(err,docs) {
});
To vrátí druhý dokument pouze proto, že pole není přítomno v jednom z dílčích dokumentů pole:
{
"id" : 2,
"line_items" : [
{
"id" : 1,
"review_request_sent" : false
},
{
"id" : 39
}
]
}
Všimněte si, že se tento "liší" od tohoto formuláře:
Model.find({
"line_items.review_request_sent": { "$exists": false }
},function(err,docs) {
})
Tam, kde se to ptá, neobsahují "všechny" prvky pole toto pole, což není pravda, pokud dokument obsahuje alespoň jeden prvek, který toto pole obsahuje. Takže $eleMatch
umožňuje testovat podmínku proti "každému" prvku pole, a tak získáte správnou odpověď.
Pokud jste chtěli aktualizovat tato data tak, aby jakýkoli nalezený prvek pole, který toto pole neobsahoval, měl toto pole obdržet s hodnotou false
(pravděpodobně ), pak byste dokonce mohli napsat prohlášení jako toto:
Model.aggregate(
[
{ "$match": {
"line_items": {
"$elemMatch": { "review_request_sent": { "$exists": false } }
}
}},
{ "$project": {
"line_items": {
"$setDifference": [
{"$map": {
"input": "$line_items",
"as": "item",
"in": {
"$cond": [
{ "$eq": [
{ "$ifNull": [ "$$item.review_request_sent", null ] },
null
]},
"$$item.id",
false
]
}
}},
[false]
]
}
}}
],
function(err,docs) {
if (err) throw err;
async.each(
docs,
function(doc,callback) {
async.each(
doc.line_items,
function(item,callback) {
Model.update(
{ "_id": doc._id, "line_items.id": item },
{ "$set": { "line_items.$.review_request_sent": false } },
callback
);
},
callback
);
},
function(err) {
if (err) throw err;
// done
}
);
}
);
Kde je .aggregate()
výsledek nejen odpovídá dokumentům, ale odfiltruje obsah z pole, kde pole nebylo přítomno, takže vrátí pouze "id" tohoto konkrétního dílčího dokumentu.
Poté zacyklený .update()
příkazy odpovídají každému nalezenému prvku pole v každém dokumentu a přidávají chybějící pole s hodnotou na odpovídající pozici.
Tímto způsobem budete mít pole přítomné ve všech dílčích dokumentech každého dokumentu, kde dříve chybělo.
Pokud chcete něco takového udělat, pak by bylo také moudré změnit schéma, abyste se ujistili, že pole je také vždy k dispozici:
{id: Number,
line_items: [{
id: String,
quantity: Number,
review_request_sent: { type: Boolean, default: false }
}],
total_price: String,
name: String,
order_number: Number
}
Takže při příštím přidání nových položek do pole ve vašem kódu bude prvek vždy existovat se svou výchozí hodnotou, pokud není výslovně nastaveno jinak. A pravděpodobně je to dobrý nápad to udělat, stejně jako nastavení required
v jiných polích, která vždy chcete, jako je „id“.