आप मूल रूप से $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()
परिणाम न केवल दस्तावेजों से मेल खाता है, बल्कि उस सरणी से सामग्री को फ़िल्टर करता है जहां फ़ील्ड मौजूद नहीं था, ताकि उस विशेष उप-दस्तावेज़ की "आईडी" को वापस कर दिया जा सके।
फिर लूप किया हुआ .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
. को सेट करना भी एक अच्छा विचार है अन्य फ़ील्ड पर जो आप हमेशा चाहते हैं, जैसे "आईडी"।