यह वास्तव में http://jira.mongodb.org/browse/SERVER-1243 पर लंबे समय से लंबित मुद्दे से संबंधित है, जहां वास्तव में "सिचुएशन सरणी मैच" वाले "सभी मामलों" का समर्थन करने वाले एक स्पष्ट सिंटैक्स के लिए कई चुनौतियां हैं। मिल गया। इस समस्या के समाधान में "सहायता" जैसे बल्क ऑपरेशन्स जैसे तथ्य पहले से मौजूद हैं जो इस मूल पोस्ट के बाद लागू किए गए हैं।
एकल अपडेट स्टेटमेंट में एकल मिलान वाले एलीमेंट तत्व से अधिक अपडेट करना अभी भी संभव नहीं है, इसलिए "मल्टी" अपडेट के साथ भी जो आप कभी भी अपडेट कर पाएंगे, उस सिंगल में प्रत्येक डॉक्यूमेंट के लिए एरे में केवल एक मैथेड एलिमेंट है बयान।
वर्तमान में सबसे अच्छा संभव समाधान सभी मिलान किए गए दस्तावेजों को ढूंढना और लूप करना है और बल्क अपडेट को संसाधित करना है जो कम से कम कई कार्यों को एक एकल प्रतिक्रिया के साथ एक ही अनुरोध में भेजने की अनुमति देगा। आप .aggregate()
खोज परिणाम में लौटी सरणी सामग्री को केवल उन लोगों के लिए वैकल्पिक रूप से उपयोग कर सकते हैं जो अपडेट चयन के लिए शर्तों से मेल खाते हैं:
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$project": {
"events": {
"$setDifference": [
{ "$map": {
"input": "$events",
"as": "event",
"in": {
"$cond": [
{ "$eq": [ "$$event.handled", 1 ] },
"$$el",
false
]
}
}},
[false]
]
}
}}
]).forEach(function(doc) {
doc.events.forEach(function(event) {
bulk.find({ "_id": doc._id, "events.handled": 1 }).updateOne({
"$set": { "events.$.handled": 0 }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
});
});
if ( count % 1000 != 0 )
bulk.execute();
.aggregate()
जब कोई ऐरे के लिए "यूनिक" आइडेंटिफायर होता है तो वह भाग काम करेगा या हर एलिमेंट के लिए सभी कंटेंट एक "यूनीक" एलिमेंट बनाते हैं। यह "सेट" ऑपरेटर के कारण होता है जो मैचों के लिए सरणी को संसाधित करने के लिए उपयोग किए गए ऑपरेशन से लौटाए गए $setDifference
किसी भी false
मान को फ़िल्टर $map
करने के लिए उपयोग किया जाता है।
यदि आपकी सरणी सामग्री में अद्वितीय तत्व नहीं हैं, तो आप इसके साथ एक वैकल्पिक दृष्टिकोण आज़मा सकते हैं $redact
:
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$redact": {
"$cond": {
"if": {
"$eq": [ { "$ifNull": [ "$handled", 1 ] }, 1 ]
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])
जहां यह सीमित है कि यदि "संभाला" वास्तव में एक क्षेत्र था जिसका अर्थ अन्य दस्तावेज़ स्तरों पर मौजूद था, तो आपको अनिर्दिष्ट परिणाम प्राप्त होने की संभावना है, लेकिन यह ठीक है कि वह क्षेत्र केवल एक दस्तावेज़ स्थिति में दिखाई देता है और एक समानता मैच है।
भविष्य के रिलीज (3.1 MongoDB) लेखन के रूप में एक $filter
ऑपरेशन होगा जो सरल है:
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$project": {
"events": {
"$filter": {
"input": "$events",
"as": "event",
"cond": { "$eq": [ "$$event.handled", 1 ] }
}
}
}}
])
और सभी रिलीज़ जो समर्थन के .aggregate()
साथ निम्नलिखित दृष्टिकोण का उपयोग कर सकते हैं $unwind
, लेकिन उस ऑपरेटर का उपयोग पाइपलाइन में सरणी विस्तार के कारण इसे कम से कम कुशल दृष्टिकोण बनाता है:
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$unwind": "$events" },
{ "$match": { "events.handled": 1 } },
{ "$group": {
"_id": "$_id",
"events": { "$push": "$events" }
}}
])
सभी मामलों में जहां MongoDB संस्करण कुल आउटपुट से एक "कर्सर" का समर्थन करता है, तो यह केवल एक दृष्टिकोण चुनने और कोड के एक ही ब्लॉक के साथ परिणामों को पुनरावृत्त करने के लिए दिखाया गया है जो बल्क अपडेट स्टेटमेंट को प्रोसेस करने के लिए दिखाया गया है। कुल उत्पादन से थोक संचालन और "कर्सर" एक ही संस्करण (MongoDB 2.6) में पेश किए जाते हैं और इसलिए आमतौर पर प्रसंस्करण के लिए हाथ से काम करते हैं।
पहले के संस्करणों में भी संभवतः .find()
कर्सर को वापस करने के लिए उपयोग करना सबसे अच्छा है, और .update()
पुनरावृत्तियों के लिए सरणी तत्व से मेल खाने वाले समय की संख्या को बयानों के निष्पादन को फ़िल्टर करना।
db.collection.find({ "events.handled": 1 }).forEach(function(doc){
doc.events.filter(function(event){ return event.handled == 1 }).forEach(function(event){
db.collection.update({ "_id": doc._id },{ "$set": { "events.$.handled": 0 }});
});
});
यदि आप "बहु" अपडेट या डीम करने के लिए निर्धारित हैं, जो अंततः प्रत्येक मिलान किए गए दस्तावेज़ के लिए कई अद्यतनों को संसाधित करने की तुलना में अधिक कुशल है, तो आप हमेशा अधिकतम सरणी मैचों की अधिकतम संख्या निर्धारित कर सकते हैं और "मल्टी" अपडेट निष्पादित कर सकते हैं, जो कि कई कई बार, जब तक कि मूल रूप से अद्यतन करने के लिए कोई और दस्तावेज़ न हों।
MongoDB 2.4 और 2.2 संस्करणों के लिए एक मान्य दृष्टिकोण भी .aggregate()
इस मूल्य को खोजने के लिए उपयोग कर सकता है :
var result = db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$unwind": "$events" },
{ "$match": { "events.handled": 1 } },
{ "$group": {
"_id": "$_id",
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": null,
"count": { "$max": "$count" }
}}
]);
var max = result.result[0].count;
while ( max-- ) {
db.collection.update({ "events.handled": 1},{ "$set": { "events.$.handled": 0 }},{ "multi": true })
}
जो भी हो, कुछ चीजें हैं जो आप अपडेट में नहीं करना चाहते हैं:
"एक शॉट" न करें सरणी को अपडेट करें: यदि आपको लगता है कि कोड में संपूर्ण सरणी सामग्री को अपडेट करने के लिए यह अधिक कुशल हो सकता है और फिर $set
प्रत्येक दस्तावेज़ में सिर्फ संपूर्ण सरणी। यह प्रक्रिया करने में तेज़ लग सकता है, लेकिन इस बात की कोई गारंटी नहीं है कि यह पढ़ने और अपडेट किए जाने के बाद से सरणी सामग्री नहीं बदली गई है। हालांकि $set
अभी भी एक परमाणु ऑपरेटर है, यह केवल सरणी को अपडेट करेगा कि यह "क्या सोचता है" सही डेटा है, और इस प्रकार पढ़ने और लिखने के बीच होने वाले किसी भी बदलाव को अधिलेखित करने की संभावना है।
अपडेट करने के लिए इंडेक्स मानों की गणना न करें: जहां "एक शॉट" दृष्टिकोण के समान आप केवल उस स्थिति 0
और स्थिति 2
(और इसी तरह) पर काम करते हैं, इन को अपडेट करने और कोड करने के लिए तत्व हैं और अंतिम विवरण जैसे:
{ "$set": {
"events.0.handled": 0,
"events.2.handled": 0
}}
यहां समस्या फिर से "अनुमान" है कि दस्तावेज़ पढ़े जाने पर उन सूचकांक मूल्यों को पाया गया जो अद्यतन के समय वें सरणी में समान सूचकांक मूल्य हैं। यदि नए आइटम को क्रम में एक तरह से जोड़ दिया जाता है जो क्रम को बदल देता है तो उन पदों को मान्य नहीं किया जाता है और गलत आइटम वास्तव में अपडेट किए जाते हैं।
इसलिए जब तक कि एक से अधिक मिलान वाले तत्वों को एकल अपडेट स्टेटमेंट में संसाधित करने की अनुमति देने के लिए एक उचित वाक्यविन्यास निर्धारित नहीं किया जाता है, तब तक मूल दृष्टिकोण या तो प्रत्येक मिलान किए गए एरे तत्व को एक अविभाज्य स्टेटमेंट (आदर्श में बल्क) में अपडेट करना है या अनिवार्य रूप से अधिकतम एरे तत्वों को काम करना है। अपडेट करने या अपडेट करने के लिए जब तक कि अधिक संशोधित परिणाम वापस न आए। किसी भी दर पर, आपको मिलान किए गए एरे तत्व पर "हमेशा" प्रसंस्करण स्थिति$
अपडेट करनी चाहिए , भले ही वह केवल एक तत्व प्रति कथन अपडेट कर रहा हो।
बल्क ऑपरेशन वास्तव में "सामान्यीकृत" समाधान है जो किसी भी ऑपरेशन को संसाधित करने के लिए "मल्टीपल ऑपरेशंस" के रूप में कार्य करता है, और चूंकि इसमें समान मूल्य के साथ केवल म्यूटेंट एरे तत्वों को अपडेट करने की तुलना में इसके लिए अधिक एप्लिकेशन हैं, फिर इसे निश्चित रूप से लागू किया गया है पहले से ही, और यह वर्तमान में इस समस्या को हल करने के लिए सबसे अच्छा तरीका है।