दिलचस्प पोस्ट
एंड्रॉइड में लाइनरलेआउट के आसपास छाया कैसे दिखाना है? आईपैड पॉपओवर की तरह आईफोन पॉपअप मेनू? मैं asyncTask पर postExecute से डेटा को कैसे वापस भेजूं? पायथन पंडस समूह द्वारा ऑब्जेक्ट विधि डुप्लिकेट पहले समूह लागू सॉर्ट करने के लिए जावा में तुलनाकर्ता का उपयोग कैसे करें Android SQLite डेटाबेस में नया कॉलम कैसे जोड़ें? कोणीय जेएस: कोणीय क्यों {angular} में {{}} से बेहतर है? पार्स स्टिंग टू फ्लोट या इंट पूर्णांक में हेक्स और हेक्स को पूर्णांक में कनवर्ट करें रॉ पोस्ट PHP में curl का उपयोग कर सूची से आइटम को हटाने – पुनरावर्तन के दौरान – इस मुहावरे में क्या गलत है? PHP और जावास्क्रिप्ट के बीच एक सरणी को स्थानांतरित करने का सर्वोत्तम तरीका Xcode 4 के साथ एक कस्टम ऐप खोलने URL स्कीम कैसे पंजीकृत करें? मैं कैसे पता लगा सकता हूँ कि किस प्रक्रिया को .NET का उपयोग कर फ़ाइल लॉक कर रही है? MySQL उपयोगकर्ता डीबी में पासवर्ड कॉलम नहीं है – OSX पर MySQL स्थापित करना

कैसे मंगलोड में कई सरणी तत्वों को अद्यतन करें

मेरे पास एक मोंगो दस्तावेज़ है जिसमें तत्वों की एक सरणी है

मैं सरणी में सभी ऑब्जेक्ट्स के .handled विशेषता रीसेट करना चाहता हूं जहां .profile = XX दस्तावेज़ निम्न रूप में है:

  { "_id" : ObjectId("4d2d8deff4e6c1d71fc29a07"), "user_id" : "714638ba-2e08-2168-2b99-00002f3d43c0", "events" : [ { "handled" : 1, "profile" : 10, "data" : "....." } { "handled" : 1, "profile" : 10, "data" : "....." } { "handled" : 1, "profile" : 20, "data" : "....." } ... ] } 

इसलिए, मैंने निम्नलिखित की कोशिश की:

 .update({"events.profile":10},{$set:{"events.$.handled":0}},false,true) 

हालांकि यह प्रत्येक दस्तावेज़ में केवल पहले मिलानित सरणी तत्व को अपडेट करता है। (यह परिभाषित व्यवहार $ – $ ऑपरेटर के लिए है ।)

मैं सभी मिलानित सरणी तत्वों को कैसे अपडेट कर सकता हूं?

वेब के समाधान से एकत्रित समाधान "कैसे मंगलोड में कई सरणी तत्वों को अद्यतन करें"

इस समय यह एक ऑरेरे में सभी आइटम्स को अपडेट करने के लिए स्थिति ऑपरेटर का उपयोग करना संभव नहीं है। JIRA http://jira.mongodb.org/browse/SERVER-1243 देखें

आपके आस-पास के एक काम के रूप में:

  • प्रत्येक आइटम को व्यक्तिगत रूप से अपडेट करें (events.0.Handled events.1.handled …) या …
  • दस्तावेज़ को पढ़ें, मैन्युअल रूप से संपादन करें और इसे पुराने की जगह ले लेते हैं (यदि आप परमाणु अपडेट सुनिश्चित करना चाहते हैं तो "अपडेट करें " यदि देखें)

मेरे लिए यह काम क्या था:

 db.collection.find({ _id: ObjectId('4d2d8deff4e6c1d71fc29a07') }) .forEach(function (doc) { doc.events.forEach(function (event) { if (event.profile === 10) { event.handled=0; } }); db.collection.save(doc); }); 

मुझे लगता है कि यह मोंगो नए और जेक्यू और दोस्तों से परिचित किसी के लिए स्पष्ट है

यह एक देर लूप के साथ भी पूरा किया जा सकता है जो यह देखने के लिए जांचता है कि क्या कोई दस्तावेज बचे हुए हैं जो अभी भी उप-दस्तावेज हैं जो अद्यतन नहीं हुए हैं। यह विधि आपके अपडेटों की परमाणुता को संरक्षित करती है (जो यहां के कई अन्य समाधान नहीं करते हैं)।

 var query = { events: { $elemMatch: { profile: 10, handled: { $ne: 0 } } } }; while (db.yourCollection.find(query).count() > 0) { db.yourCollection.update( query, { $set: { "events.$.handled": 0 } }, { multi: true } ); } 

लूप की संख्या को निष्पादित करने की संख्या अधिकतम संख्या के बराबर होगी, उप-दस्तावेजों को 10 के बराबर profile साथ और आपके संग्रह में किसी भी दस्तावेज़ में 0 के बराबर नहीं handled । इसलिए यदि आपके पास अपने संग्रह में 100 दस्तावेज हैं और उनमें से एक में तीन उप-दस्तावेज हैं जो query मेल खाते हैं और अन्य सभी दस्तावेजों में कम मिलान वाले उप-दस्तावेजों हैं, तो लूप तीन बार निष्पादित करेगा।

यह विधि अन्य डेटा को क्लॉबिंग करने के खतरे से बचा जाता है जो कि किसी अन्य प्रक्रिया द्वारा अपडेट किया जा सकता है, जबकि यह स्क्रिप्ट कार्यान्वित करता है। यह क्लाइंट और सर्वर के बीच स्थानांतरित होने वाले डेटा की मात्रा को भी कम करता है।

यह वास्तव में 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 सेट में "सेट" ऑपरेटर के कारण है, मैचों के लिए सरणी की प्रक्रिया के लिए इस्तेमाल किए गए $map ऑपरेशन से लौटाए गए किसी भी false मान को फ़िल्टर करने के लिए उपयोग किया जाता है।

यदि आपकी सरणी सामग्री के पास अद्वितीय तत्व नहीं हैं तो आप $redact साथ एक वैकल्पिक दृष्टिकोण की कोशिश कर सकते हैं:

 db.collection.aggregate([ { "$match": { "events.handled": 1 } }, { "$redact": { "$cond": { "if": { "$eq": [ { "$ifNull": [ "$handled", 1 ] }, 1 ] }, "then": "$$DESCEND", "else": "$$PRUNE" } }} ]) 

जहां इसकी सीमा होती है, वास्तव में अगर किसी क्षेत्र के अन्य दस्तावेज स्तर पर उपस्थित होने का मतलब "संभाला" होता है तो आप अप्रत्याशित परिणाम प्राप्त करने जा रहे हैं, लेकिन यह ठीक है, जहां वह क्षेत्र केवल एक दस्तावेज़ स्थिति में प्रकट होता है और एक समानता मैच होता है।

भविष्य के रिलीज (पोस्ट 3.1 मोंगोडीबी) लिखित रूप में एक $filter ऑपरेशन होगा जो सरल होता है:

 db.collection.aggregate([ { "$match": { "events.handled": 1 } }, { "$project": { "events": { "$filter": { "input": "$events", "as": "event", "cond": { "$eq": [ "$$event.handled", 1 ] } } } }} ]) 

और सभी रिलीज जो समर्थन करते हैं। कुल .aggregate() $unwind .aggregate() साथ निम्नलिखित दृष्टिकोण का उपयोग कर सकते हैं, लेकिन पाइप लाइन में सरणी विस्तार के कारण उस ऑपरेटर का उपयोग कम से कम कुशल दृष्टिकोण बनाता है:

 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 }) } 

जो भी मामला है, वहाँ कुछ चीजें हैं जो आप अद्यतन के भीतर नहीं करना चाहते हैं:

  1. "एक शॉट" को सरणी का अद्यतन न करें: यदि आपको लगता है कि यह कोड में संपूर्ण ऑरेरे सामग्री को अपडेट करने के लिए और अधिक सक्षम हो सकता है और फिर प्रत्येक दस्तावेज़ में केवल $set पूरी सरणी $set कर सकता है यह प्रक्रिया में तेज़ी से लग सकता है, लेकिन इसकी कोई गारंटी नहीं है कि अरै सामग्री पढ़ी गई है, क्योंकि यह पढ़ा गया था और अपडेट किया गया है। हालांकि $set अभी भी एक परमाणु ऑपरेटर है, यह केवल सही डेटा के साथ "सरणी" को अद्यतन करेगा, और इस प्रकार पढ़ने और लिखने के बीच होने वाले किसी भी परिवर्तन को ओवरराइट करने की संभावना है।

  2. अद्यतन करने के लिए सूचकांक मूल्यों की गणना न करें: जहां "एक शॉट" दृष्टिकोण के समान आप बस उस स्थिति 0 और स्थिति 2 (और इसी तरह) को तैयार करते हैं, इन्हें अपडेट करने और इनके साथ अंतिम सम्बन्ध की तरह के कोड के लिए तत्व होते हैं:

     { "$set": { "events.0.handled": 0, "events.2.handled": 0 }} 

    दोबारा समस्या यहाँ "अनुमान" है कि उन सूचकांक मूल्यों को मिला जब दस्तावेज़ पढ़ा गया था, अद्यतन के समय वें इंडेक्स में एक ही इंडेक्स वैल्यू। यदि नई वस्तुओं को सरणी में जोड़ा जाता है तो ऑर्डर बदलता है, तो उन स्थितियां अधिक मान्य नहीं होतीं और गलत आइटम वास्तव में अपडेट किए गए थे।

इसलिए जब तक एक मिलान वाक्यविन्यास विवरण में एकाधिक मिलान किए गए सरणी तत्वों को संसाधित करने की अनुमति देने के लिए एक उचित सिंटैक्स निर्धारित नहीं किया जाता है, तब तक मूल दृष्टिकोण यह है कि या तो एक आंशिक बयान में प्रत्येक मिलानित सरणी तत्व को अपडेट किया जाए (आदर्श रूप में बल्क में) या अनिवार्य रूप से अधिकतम सरणी तत्व अद्यतन करने के लिए या अद्यतन करने तक कोई और संशोधित परिणाम नहीं लौटाए जाते हैं किसी भी दर पर, आपको "हमेशा" मिलान किए गए सरणी तत्व पर स्थितीय $ अपडेट प्रसंस्करण होना चाहिए, भले ही वह केवल एक प्रति कथन प्रत्येक कथन को अपडेट कर रहा है

बल्क ऑपरेशंस वास्तव में "एकाधिक ऑपरेशन" के लिए काम करने वाले किसी भी परिचालन के समाधान के लिए "सामान्यीकृत" समाधान में हैं, और इसके बाद से केवल उसी मूल्य के साथ कई सरणी तत्वों को अद्यतन करने के लिए इसके अधिक अनुप्रयोग हैं, तो यह निश्चित रूप से लागू किया गया है पहले से ही, और यह वर्तमान में इस समस्या को हल करने का सबसे अच्छा तरीका है।

मुझे आश्चर्य है कि अभी भी मोंगो में संबोधित नहीं किया गया है। उप-एरे से निपटने के दौरान समग्र मोंगो महान नहीं लगता है। उदाहरण के लिए आप केवल उप-ऑरेन्स नहीं गिना सकते।

मैंने जेवियर का पहला समाधान इस्तेमाल किया घटनाओं में सरणी को पढ़ो, फिर लूप के माध्यम से और सेट एक्सपर्च का निर्माण करें:

 var set = {}, i, l; for(i=0,l=events.length;i<l;i++) { if(events[i].profile == 10) { set['events.' + i + '.handled'] = 0; } } .update(objId, {$set:set}); 

सशर्त परीक्षण के लिए कॉलबैक का उपयोग करके यह फ़ंक्शन में समझा जा सकता है

MongoDB 3.6 (और MongoDB 3.5.12 से विकास शाखा में उपलब्ध) के रिलीज के साथ अब आप एकल अनुरोध में एकाधिक सरणी तत्वों को अपडेट कर सकते हैं।

यह फ़िल्टर्ड स्थितिबद्ध $[<identifier>] अद्यतन संस्करण को इस संस्करण में पेश किया गया है:

 db.collection.update( { "events.profile":10 }, { "$set": { "events.$[elem].handled": 0 } }, { "arrayFilters": [{ "elem.profile": 10 }], "multi": true } ) 

"arrayFilters" .update() या .updateOne() , .updateMany() , .findOneAndUpdate() या .bulkWrite() विधि के लिए विकल्पों को पारित के रूप में "arrayFilters" अद्यतन कथन में दिए गए पहचानकर्ता पर मिलान करने के लिए शर्तों को निर्दिष्ट करता है। दी गई स्थिति से मेल खाने वाले किसी तत्व को अपडेट किया जाएगा।

यह ध्यान देते हुए कि प्रश्न के संदर्भ में दिए गए "multi" का उपयोग उम्मीद में किया गया था कि यह "कई तत्वों को अपडेट करेगा" लेकिन यह नहीं था और फिर भी यह मामला नहीं है। इसका उपयोग यहां "एकाधिक दस्तावेज़" पर लागू होता है क्योंकि यह हमेशा मामला होता है या फिर आधुनिक API संस्करणों में .updateMany() की अनिवार्य सेटिंग के रूप में निर्दिष्ट होता है।

नोट कुछ हद तक विडंबना यह है कि चूंकि यह .update() लिए "विकल्प" तर्क में निर्दिष्ट है और तरीकों की तरह, वाक्यविन्यास आमतौर पर सभी हालिया रिलीज़ ड्राइवर संस्करणों के साथ संगत है।

हालांकि यह mongo खोल के बारे में सच नहीं है, क्योंकि विधि जिस तरह से कार्यान्वित होती है ("विडंबनात्मक रूप से पिछड़े संगतता के लिए") arrayFilters तर्क को एक आंतरिक विधि से पहचाना नहीं जाता है और इसे हटाया जाता है ताकि "पिछड़े संगतता" पूर्व MongoDB सर्वर संस्करण और एक "विरासत" .update() API कॉल वाक्यविन्यास के साथ

इसलिए यदि आप mongo शेल या अन्य "शेल आधारित" उत्पादों (विशेषकर रोबो 3T) में कमांड का उपयोग करना चाहते हैं तो आपको या तो विकास शाखा या 3.6 या उससे अधिक के रूप में उत्पादन रिलीज से नवीनतम संस्करण की आवश्यकता है।

positional all $[] भी देखें जो कि "अनेक सरणी तत्वों" को भी अपडेट करते हैं, लेकिन निर्दिष्ट स्थितियों के लिए आवेदन किए बिना और सरणी के सभी तत्वों पर लागू होता है जहां वांछित क्रिया है

इसके अलावा MongoDB के साथ एक नेस्टेड ऐरे को अपडेट करने के लिए देखें कि इन नए स्थानीयक ऑपरेटर्स "नेस्टेड" सरणी संरचनाओं पर कैसे लागू होते हैं, जहां "एरे अन्य एरेज़ में हैं"

मैं सिर्फ एक और समाधान जोड़ना चाहता था जो मेरे लिए काम करता था और बहुत आसान है। यहाँ यह सिर्फ एक सरणी है (स्ट्रिंग्स) ताकि "बदल" के लिए "परीक्षण" नामक एक टैग को अपडेट करने के लिए, बस ऐसा करें:

 myDocuments.find({tags: "test" }, {fields: {_id: 1}}).forEach(function (doc) { myDocuments.update( {_id: doc._id, tags: "test"}, {$set:{'tags.$': "changed"}}); }); 

दरअसल, सहेजें कमांड केवल दस्तावेज़ कक्षा के उदाहरण पर है इसमें बहुत सारे विधियों और विशेषताएँ हैं तो आप लोड लोड को कम करने के लिए दुबला () फ़ंक्शन का उपयोग कर सकते हैं। यहाँ देखें https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j

समारोह को बचाने के साथ एक और समस्या है, जो एक ही समय में बहु-सहेजने के साथ संघर्ष डेटा बना देगा। Model.Update डेटा को लगातार बनाएगा तो दस्तावेज़ की सरणी में बहु आइटम्स को अपडेट करने के लिए अपनी परिचित प्रोग्रामिंग भाषा का प्रयोग करें और इस तरह से कुछ करने का प्रयास करें, मैं उस में मोंगोज का उपयोग करता हूं:

 User.findOne({'_id': '4d2d8deff4e6c1d71fc29a07'}).lean().exec() .then(usr =>{ if(!usr) return usr.events.forEach( e => { if(e && e.profile==10 ) e.handled = 0 }) User.findOneAndUpdate( {'_id': '4d2d8deff4e6c1d71fc29a07'}, {$set: {events: usr.events}}, {new: true} ).lean().exec().then(updatedUsr => console.log(updatedUsr)) }) 

मैंने निम्नलिखित की कोशिश की और इसके ठीक काम करने की कोशिश की।

 .update({'events.profile': 10}, { '$set': {'events.$.handled': 0 }},{ safe: true, multi:true }, callback function); 

नोडजे के मामले में // कॉलबैक फ़ंक्शन