Ответ 1
В основном вы хотите $elemMatch
и $exists
, так как это проверит каждый элемент, чтобы убедиться, что условие "поле не существует" истинно для любого элемента:
Model.find({
"line_items": {
"$elemMatch": { "review_request_sent": { "$exists": false } }
}
},function(err,docs) {
});
Это возвращает второй документ только в том случае, если поле не присутствует в одном из поддокументов массива:
{
"id" : 2,
"line_items" : [
{
"id" : 1,
"review_request_sent" : false
},
{
"id" : 39
}
]
}
Обратите внимание, что это "отличается" от этой формы:
Model.find({
"line_items.review_request_sent": { "$exists": false }
},function(err,docs) {
})
В этом вопросе "все" элементов массива не содержат этого поля, что неверно, если в документе есть хотя бы один элемент, в котором есть данное поле. Таким образом, параметр $eleMatch
проверяет условие на элемент "каждый", и вы получаете правильный ответ.
Если вы хотите обновить эти данные, чтобы любой найденный элемент массива, который не содержал это поле, должен был получить это поле со значением false
(предположительно), тогда вы могли бы даже написать инструкцию следующим образом:
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
}
);
}
);
Где результат .aggregate()
не только совпадает с документами, но и фильтрует содержимое из массива, где это поле отсутствует, чтобы просто вернуть "id" этого конкретного поддоку.
Затем петлевые операторы .update()
соответствуют каждому найденному элементу массива в каждом документе и добавляют недостающее поле со значением в согласованной позиции.
Таким образом, у вас будет поле, присутствующее во всех поддокументах каждого документа, где он отсутствовал раньше.
Если вы хотите сделать что-то подобное, тогда было бы разумно изменить вашу схему, чтобы убедиться, что поле всегда там:
{id: Number,
line_items: [{
id: String,
quantity: Number,
review_request_sent: { type: Boolean, default: false }
}],
total_price: String,
name: String,
order_number: Number
}
Итак, в следующий раз, когда вы добавите новые элементы в массив в вашем коде, элемент всегда будет существовать с его значением по умолчанию, если иное не задано явно. И это, вероятно, идея goood для этого, а также установка required
в другие поля, которые вы всегда хотите, такие как "id".