कैसे mongodb में एकाधिक सरणी तत्वों को अद्यतन करने के लिए


183

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

मैं .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)

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

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


2
सबटेट या सभी एरे आइटम को अपडेट करने के लिए मोंगोडब 3.6 में जोड़ा गया है: डॉक्स.mongodb.com/manual/reference/operator/update/…
Jaap

ऐरेफिल्टर्स की जाँच करना सुनिश्चित करें और अपडेट को कुशल बनाने के लिए किस क्वेरी का उपयोग करें, इस पर विचार करें। नील लुन द्वारा उत्तर देखें: stackoverflow.com/a/46054172/337401
जाप

मेरे जवाब की जाँच करें
Ucdemir

जवाबों:


111

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

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

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

15
अगर आपको इसी तरह की समस्या है, तो इस मुद्दे पर वोट करें - jira.mongodb.org/browse/SERVER-1243
LiorH

मैं वास्तव में रीड डॉक्यूमेंट और सेव एप्रोच को पसंद करता हूं। लेकिन मैंने मोंगो से पहले काउच का उपयोग किया ताकि दृष्टिकोण अधिक स्वाभाविक लगे क्योंकि काउच के लिए कोई क्वेरी एपीआई नहीं है, पूरे दस्तावेजों के लिए सिर्फ एक रीस्ट एपीआई
एडमंड

1
इन दोनों तरीकों के लिए बहुत अधिक मात्रा में मेमोरी की आवश्यकता होती है, है ना? अगर वहाँ बहुत सारे दस्तावेज़ हैं जिन्हें खोजा जाना है, और अपडेट करने के लिए उन सभी (या नेस्टेड सरणियों) को लोड करना है ... + इसे लागू करने के लिए थोड़ा परेशानी भरा है अगर इसे अतुल्यकालिक रूप से किया जाना है ...
Ixx

13
एक तरफ सभी तकनीकी कठिनाइयों, यह आश्चर्यजनक है कि यह सुविधा MongoDB में उपलब्ध नहीं है। यह बाधा डेटाबेस स्कीमा को अनुकूलित करने से बहुत अधिक स्वतंत्रता लेती है।
चो

5
नील लुन stackoverflow.com/a/46054172/337401 संस्करण 3.6 के लिए यह जवाब दे दिया। चूँकि यह एक लोकप्रिय प्रश्न है, इसलिए यह इस योग्य उत्तर को अद्यतन करने के लिए लायक हो सकता है, क्योंकि नील लुन द्वारा उत्तर के लिए एक रेफरल दिया गया है।
जाप

74

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()विधि निर्दिष्ट स्थिति अद्यतन बयान में दिए गए पहचानकर्ता पर मैच के लिए। जो भी तत्व दिए गए शर्त से मेल खाते हैं उन्हें अपडेट किया जाएगा।

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

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

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

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

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

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

महत्वपूर्ण - पिछले संस्करणों से उन्नत इंस्टॉलेशन "हो सकता है" ने MongoDB विशेषताओं को सक्षम नहीं किया है, जो बयानों को विफल करने का कारण भी बन सकता है। आपको यह सुनिश्चित करना चाहिए कि आपकी अपग्रेड प्रक्रिया इंडेक्स अपग्रेड और फिर रन जैसे विवरण के साथ पूरी हो

   db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )

या उच्चतर संस्करण आपके स्थापित संस्करण पर लागू होता है। यानी "4.0"संस्करण 4 के लिए और उसके बाद वर्तमान में। इसने इस तरह की सुविधाओं को नए स्थितीय अद्यतन ऑपरेटरों और अन्य के रूप में सक्षम किया। आप इसके साथ भी देख सकते हैं:

   db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

वर्तमान सेटिंग को वापस करने के लिए


10
स्वीकृत उत्तर को अद्यतन किया जाना चाहिए और इस उत्तर को देखें।
जाप

3
क्या है elem?
user1063287

1
यह सही है। ध्यान दें कि RoboMongo arrayFiltersअभी तक समर्थन नहीं करता है, इसलिए CLI के माध्यम से अपडेट चल रहा है। stackoverflow.com/questions/48322834/…
drlff

धन्यवाद, नील, विशेष रूप से महत्वपूर्ण अनुभाग के लिए, वास्तव में मुझे क्या चाहिए
jffabian

यह कोड प्योंगो में ERROR देता है। तेहर त्रुटि है: टाइपएयरर को बढ़ाएं ("% s सही होना चाहिए या गलत"% (विकल्प,) टाइप टाइप): अपटाउन सही होना चाहिए या गलत
वागिफ

67

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

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

मुझे लगता है कि यह mongo newbies और JQuery और दोस्तों से परिचित किसी के लिए भी स्पष्ट है।


मैं का उपयोग कर रहा हूँ db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...और मैं कर रहा हूँOops.. TypeError: Object # has no method 'forEach'
स्क्वीरेल

3
@Squirrl पुराना mongodb संस्करण हो सकता है? डॉक्स स्पष्ट है कि किसी कर्सर पर forEach फ़ंक्शन को कैसे लागू किया जाए, लेकिन यह निर्दिष्ट नहीं करता है कि कौन सा संस्करण समर्थित है। docs.mongodb.org/manual/reference/method/cursor.forEach
डैनियल सेरेकेडो

कोशिश @Squirrldb.posts.find(...).toArray().forEach(...)
marmor

क्या हम बिना उपयोग के ऐसा नहीं कर सकते Javascript? मैं जावास्क्रिप्ट एपीआई का उपयोग किए बिना एक मोंगू शेल से सीधे इस अपडेट को करना चाहता हूं।
मेलिओदास

1
क्या आप इस प्रश्न को जांग के लिए मोंगोडब ड्राइवर में लिख सकते हैं या वसंत-डेटा-मोंगोडब के साथ? धन्यवाद,
क्रिश

18

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

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

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

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


13

यह वास्तव में 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 })
}

जो भी हो, कुछ चीजें हैं जो आप अपडेट में नहीं करना चाहते हैं:

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

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

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

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

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

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


8

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

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

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

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


इसके लिए धन्यवाद! विश्वास नहीं कर सकता यह सुविधा अभी भी मूल रूप से समर्थित नहीं है! यह सबर्रे के प्रत्येक आइटम को बढ़ाने के लिए उपयोग किया जाता है, दूसरों को पढ़ने के लिए ... हर आइटम को अपडेट करने के लिए बस अगर कथन को हटा दें।
जहीर

9
यह एक सुरक्षित उपाय नहीं है। यदि आप अपडेट चलाते समय कोई रिकॉर्ड जोड़ते हैं, तो आप अपना डेटा दूषित कर देंगे।
मर्क

4

मैं सी # 3.6 के लिए नवीनतम ड्राइवर का उपयोग करके इसके समाधान की तलाश कर रहा हूं और यह तय है कि मैं आखिरकार बस गया। यहाँ कुंजी "$ []" का उपयोग कर रही है जो MongoDB के अनुसार संस्करण 3.6 के रूप में नया है। Https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up देखें S [] अधिक जानकारी के लिए।

यहाँ कोड है:

{
   var filter = Builders<Scene>.Filter.Where(i => i.ID != null);
   var update = Builders<Scene>.Update.Unset("area.$[].discoveredBy");
   var result = collection.UpdateMany(filter, update, new UpdateOptions { IsUpsert = true});
}

अधिक संदर्भ के लिए मेरी मूल पोस्ट यहाँ देखें: MongoDB C # ड्राइवर का उपयोग करके सभी दस्तावेज़ों से सरणी तत्व निकालें


4

धागा बहुत पुराना है, लेकिन मैं यहां उत्तर की तलाश में आया था इसलिए नए समाधान प्रदान कर रहा हूं।

MongoDB संस्करण 3.6+ के साथ, अब किसी सरणी में सभी आइटम को अपडेट करने के लिए स्थितीय ऑपरेटर का उपयोग करना संभव है। आधिकारिक दस्तावेज यहां देखें ।

निम्नलिखित प्रश्न यहां पूछे गए प्रश्न के लिए काम करेंगे। मैंने Java-MongoDB ड्राइवर के साथ भी सत्यापन किया है और यह सफलतापूर्वक काम करता है।

.update(   // or updateMany directly, removing the flag for 'multi'
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},  // notice the empty brackets after '$' opearor
   false,
   true
)

आशा है कि यह मेरे जैसे किसी की मदद करेगा।


1

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

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

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


यह कोड केवल सरणी में पहले मिलान किए गए आइटम को अपडेट करता है। गलत जवाब।
हेमलेट

यह v2.6 के लिए काम करता है। आप पुराने संस्करण में हो सकते हैं? यहाँ इसके डॉक्स डॉक्समोंगबब.com
manual/

1

आप MongoDB में सभी तत्वों को अपडेट कर सकते हैं

db.collectioname.updateOne(
{ "key": /vikas/i },
{ $set: { 
 "arr.$[].status" : "completed"
} }
)

यह "गिरफ्तार" ऐरे में "पूरा" मूल्य के सभी "स्टेटस" को अपडेट करेगा

यदि केवल एक दस्तावेज़

db.collectioname.updateOne(
 { key:"someunique", "arr.key": "myuniq" },
 { $set: { 
   "arr.$.status" : "completed", 
   "arr.$.msgs":  {
                "result" : ""
        }
   
 } }
)

लेकिन अगर एक भी नहीं और आप भी नहीं चाहते हैं कि सरणी के सभी दस्तावेज अपडेट हो जाएं तो आपको तत्व के माध्यम से और अगर ब्लॉक में लूप करने की आवश्यकता है

db.collectioname.find({findCriteria })
  .forEach(function (doc) {
    doc.arr.forEach(function (singlearr) {
      if (singlearr check) {
        singlearr.handled =0
      }
    });
    db.collection.save(doc);
  });

0

दरअसल, सेव कमांड केवल डॉक्यूमेंट क्लास के उदाहरण पर है। जिसमें बहुत सारी विधियाँ और विशेषताएँ हैं। तो आप काम के बोझ को कम करने के लिए दुबला () फ़ंक्शन का उपयोग कर सकते हैं । यहाँ देखें। 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))
})

0

$ [] ऑपरेटर सभी नेस्टेड सरणी का चयन करता है .. आप सभी सरणी आइटम को '$ []' के साथ अपडेट कर सकते हैं

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

संदर्भ


क्या आप कृपया समझा सकते हैं कि आप यहाँ अंत में "असत्य, सत्य" को क्यों शामिल करते हैं? मैं इसे प्रलेखन में नहीं ढूँढ सकता।
गार्सन

गलत सभी उत्तरदाता ऑपरेटर का जवाब देते हैं $[] बस निर्दिष्ट सरणी में सभी फ़ील्ड्स को अपडेट करता है। फ़िल्टर किए गए स्थितीय ऑपरेटर क्या काम करते हैं, जो $[identifier]सरणी फ़ील्ड्स पर ऑपरेटर निर्दिष्ट शर्तों से मेल खाते हैं। साथ किया जाना चाहिए arrayFilters : Refrence docs.mongodb.com/manual/release-notes/3.6/#arrayfilters और docs.mongodb.com/manual/reference/operator/update/...
लॉरेंस ईगल्स

0

कृपया ध्यान रखें कि इस धागे में कुछ जवाब $ [] का उपयोग करने का सुझाव देते हैं।

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

उपरोक्त कोड "ईवेंट" सरणी के सभी तत्वों के लिए "हैंडल" को अपडेट करेगा, भले ही इसका "प्रोफ़ाइल" मान कुछ भी हो। क्वेरी {"events.profile":10}केवल संपूर्ण दस्तावेज़ को फ़िल्टर करने के लिए है, न कि सरणी में दस्तावेज़ों के लिए। इस स्थिति में इसका इस्तेमाल करने की बहुत जरूरी है $[elem]साथ arrayFiltersतो नील लुन के जवाब सही है सरणी मदों की हालत निर्दिष्ट करने के लिए।


0

मोंगो डीबी में कई दस्तावेज़ों में सरणी फ़ील्ड अपडेट करें।

MongoDb में सरणी तत्वों को अपडेट करने के लिए कई क्वेरी को अपडेट के साथ $ पुल या $ पुश का उपयोग करें।

Notification.updateMany(
    { "_id": { $in: req.body.notificationIds } },
    {
        $pull: { "receiversId": req.body.userId }
    }, function (err) {
        if (err) {
            res.status(500).json({ "msg": err });
        } else {
            res.status(200).json({
                "msg": "Notification Deleted Successfully."
            });
        }
    });

0

पहला: आपका कोड काम नहीं करता था क्योंकि आप स्थितीय ऑपरेटर का उपयोग कर रहे थे $ जो केवल एक सरणी में अद्यतन करने के लिए एक तत्व की पहचान करता है, लेकिन सरणी में अपनी स्थिति को स्पष्ट रूप से निर्दिष्ट नहीं करता है।

आपको फ़िल्टर किए गए स्थितीय ऑपरेटर की आवश्यकता है $[<identifier>]। यह उन सभी तत्वों को अद्यतन करेगा जो एक सरणी फ़िल्टर स्थिति से मेल खाते हैं।

उपाय:

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

Mongodb डॉक्टर के यहाँ जाएँ

कोड क्या करता है:

  1. {"events.profile":10} अपने संग्रह को फ़िल्टर करता है और फ़िल्टर से मेल खाते दस्तावेज़ों को वापस करता है

  2. $setअद्यतन ऑपरेटर: दस्तावेजों के क्षेत्र मिलान संशोधित उस पर कार्य करता है।

  3. {multi:true}यह .update()फिल्टर से मेल खाने वाले सभी दस्तावेजों को संशोधित करता है इसलिए व्यवहार करना पसंद करता हैupdateMany()

  4. { "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ] इस तकनीक में arrayFilters के साथ फ़िल्टर्ड स्थितीय सरणी का उपयोग शामिल है। फ़िल्टर्ड स्थितीय सरणी यहाँ $[elem]सरणी फ़ील्ड में सभी तत्वों के लिए प्लेसहोल्डर के रूप में कार्य करती है जो सरणी फ़िल्टर में निर्दिष्ट शर्तों से मेल खाती है।

फिल्टर फिल्टर

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.