你基本上想要$elemMatch http://docs.mongodb.org/master/reference/operator/query/elemMatch/和$exists http://docs.mongodb.org/master/reference/operator/query/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
}
因此,下次您在代码中向数组添加新项目时,如果没有明确设置,该元素将始终以其默认值存在。这样做以及设置可能是一个好主意required
在您总是想要的其他字段上,例如“id”。