2012-05-09 17 views
143

मान लें हम निम्नलिखित संग्रह है, जो मैं के बारे में कुछ प्रश्न हैं है:MongoDB - अद्यतन दस्तावेज़ की सरणी (नेस्ट अपडेट करना) में वस्तुओं

{ 
    "_id" : ObjectId("4faaba123412d654fe83hg876"), 
    "user_id" : 123456, 
    "total" : 100, 
    "items" : [ 
      { 
        "item_name" : "my_item_one", 
        "price" : 20 
      }, 
      { 
        "item_name" : "my_item_two", 
        "price" : 50 
      }, 
      { 
        "item_name" : "my_item_three", 
        "price" : 30 
      } 
    ] 
} 

1 - मैं "ITEM_NAME" के लिए कीमत में वृद्धि करना चाहते हैं: " my_item_two "और यदि यह मौजूद नहीं है, तो इसे" आइटम "सरणी में जोड़ा जाना चाहिए।

2 - मैं एक ही समय में दो फ़ील्ड कैसे अपडेट कर सकता हूं। उदाहरण के लिए, "my_item_three" के लिए कीमत बढ़ाएं और साथ ही साथ "कुल" (उसी मान के साथ) बढ़ाएं।

मैं इसे मोंगोडीबी पक्ष पर करना पसंद करता हूं, अन्यथा मुझे क्लाइंट-साइड (पायथन) में दस्तावेज़ लोड करना होगा और अपडेट किए गए दस्तावेज़ का निर्माण करना होगा और इसे मोंगोडीबी में मौजूदा एक के साथ बदलना होगा।

अद्यतन यह मैं क्या कोशिश की है और ठीक काम करता है यदि वस्तु मौजूद है:

db.test_invoice.update({user_id : 123456 , "items.item_name":"my_item_one"} , {$inc: {"items.$.price": 10}}) 

लेकिन अगर कुंजी मौजूद नहीं है यह कुछ नहीं करता है। इसके अलावा यह केवल नेस्टेड ऑब्जेक्ट को अपडेट करता है। इस आदेश के साथ "कुल" फ़ील्ड को अपडेट करने का कोई तरीका नहीं है।

+1

मुझे लगता है कि आप इसे मोंगो में नहीं कर सकते हैं, सिवाय इसके कि बहुत से दर्द का उपयोग करके। मोंगो डेटा ऑप्स में बहुत सीमित है। –

+3

@ हापाला: मोंगोडब के पास $ इंकर्ट – jdi

+1

@jdi हां हां के साथ $ inc और अपडेट है, लेकिन यह यहां बहुत मदद नहीं करता है, लेकिन उसे जो चाहिए वह कई $ incs है, सशर्त रूप से, और यदि आइटम मौजूद नहीं है, तो एक $ पुश है जरूरत है। –

उत्तर

173

प्रश्न # 1 के लिए, इसे दो भागों में तोड़ दें। सबसे पहले, किसी भी दस्तावेज़ को बढ़ाएं जिसमें "item.item_name" "my_item_two" के बराबर है। इसके लिए आपको स्थितित्मक "$" ऑपरेटर का उपयोग करना होगा। कुछ की तरह:

db.bar.update({user_id : 123456 , "items.item_name" : "my_item_two" } , 
       {$inc : {"items.$.price" : 1} } , 
       false , 
       true); 

ध्यान दें कि यह केवल किसी भी श्रेणी में सबसे पहले मिलने वाला subdocument बढ़ेगी, जब (ताकि आप के साथ सरणी में किसी अन्य दस्तावेज़ है, तो "ITEM_NAME" बराबर करने के लिए "my_item_two", यह वृद्धि नहीं किया जाएगा) । लेकिन यह वही हो सकता है जो आप चाहते हैं।

दूसरा भाग ट्रिकियर है। हम एक "my_item_two" इस प्रकार के बिना एक सरणी में कोई नया आइटम धक्का कर सकते हैं:

db.bar.update({user_id : 123456, "items.item_name" : {$ne : "my_item_two" }} , 
       {$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } , 
       false , 
       true); 

अपने प्रश्न # 2 के लिए, इस सवाल का जवाब आसान है। किसी भी दस्तावेज़ में item_three के कुल और मूल्य को बढ़ाने के लिए जिसमें "my_item_three" है, आप एक साथ कई फ़ील्ड पर $ inc inc ऑपरेटर का उपयोग कर सकते हैं। कुछ ऐसा:

db.bar.update({"items.item_name" : {$ne : "my_item_three" }} , 
       {$inc : {total : 1 , "items.$.price" : 1}} , 
       false , 
       true); 
+0

उत्तर के लिए धन्यवाद। प्रश्न # 2 का उत्तर सही है और ठीक काम करता है :) लेकिन प्रश्न # 1 के लिए, समस्या यह है कि आपको "user_id" द्वारा दस्तावेज़ की खोज करनी चाहिए, न कि "items.item_name" द्वारा। इस मामले में मैं स्थितित्मक ऑपरेटर का उपयोग नहीं कर सकता, क्योंकि मैंने खोज क्वेरी में सरणी निर्दिष्ट नहीं की है। इसके अलावा मैं चाहता हूं कि दोनों हिस्सों को एक शॉट में किया जाए। (यदि संभव हो) – Majid

+0

अच्छे उदाहरण। मुझे लगा जैसे मैं अपने उत्तर में दिए गए लिंक से यह दिशा स्पष्ट कर रहा था, लेकिन मैं प्रतिरोध कह रहा था कि वह क्या नहीं ढूंढ रहा था। ओपी का अनुमान लगाएं कि कई $ inc कैसे करें इस पर उदाहरण देखने के लिए बस जरूरी है। – jdi

+0

प्रश्न # 1 के लिए, आपको अभी भी प्रत्येक अपडेट के क्वेरी बिट पर user_id जोड़कर दो भागों में ऐसा करने में सक्षम होना चाहिए (मैं तदनुसार उत्तर संशोधित करूंगा)। एक शॉट में करना संभव है या नहीं, इसके बारे में और सोचना होगा। – matulef

19

एकल क्वेरी में ऐसा करने का कोई तरीका नहीं है।

db.bar.update({user_id : 123456 , "items.item_name" : "my_item_two" } , 
       {$inc : {"items.$.price" : 1} } , 
       false , 
       true); 

वरना

db.bar.update({user_id : 123456 } , 
       {$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } , 
       false , 
       true); 

कोई ज़रूरत नहीं हालत {$ne : "my_item_two" } जोड़ने के लिए:

दस्तावेज़ मौजूद है: आप दस्तावेज़ खोज करने के लिए पहली क्वेरी में है।

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

+1

नहीं, एक प्रश्न में ऐसा करने का एक तरीका है, ऊपर देखें –

+0

@MartijnScheffer, मुझे इस धागे में कहीं भी एक प्रश्न के रूप में ऐसा करने का कोई तरीका नहीं दिख रहा है। यहां तक ​​कि "उत्तर" इस ​​प्रश्न में 2 प्रश्नों का उपयोग कर रहा है। क्या मैं कुछ भूल रहा हूँ? मैं यह भी उम्मीद कर रहा हूं कि किसी भी बहु थ्रेडिंग समस्याओं को रोकने के लिए एक प्रश्न में ऐसा करने का कोई तरीका है – dferraro

+0

@Udit, मैं आइटम का उपयोग कैसे कर सकता हूं। $। कीमत के अंदर कीमत? जब मैं एक शर्त जोड़ने की कोशिश करता हूं जैसे कि "वृद्धि केवल तभी बढ़ती है जब कीमत 0 से अधिक हो", यह काम नहीं करती - मूल रूप से कुछ भी अपडेट नहीं हो जाता है। क्या मैं इसे कहां स्थित कर सकता हूं, या क्या मुझे कुछ याद आ रहा है? आइटम। $ मूल्य: {$ gt: 0} – dferraro

संबंधित मुद्दे