2012-01-15 13 views
9

How do I update Array Elements matching criteria in a MongoDB document?एक मोंडोडीबी दस्तावेज़ में अपरर्ट ऐरे तत्व मिलान मानदंड?

मैं सरणी तत्वों को अपरिवर्तित करना चाहता हूं, इसलिए यदि कोई मेल नहीं खाता है तो उसे डालें, अन्यथा इसे अपडेट करें।

मैंने उस प्रश्न का उत्तर देने की कोशिश की, और यह ठीक काम करता है अगर सरणी तत्व पहले से मौजूद है। यदि तत्व मौजूद नहीं है तो यह सरणी क्षेत्र के नीचे "$" का बच्चा बनाता है।

मेरे मोंगो संरचना इस प्रकार है:

Widget (collection) 
--Name 
--Properties (array) 
    --Name 
    --Value 

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

उत्तर

10

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

जिस समस्या में आप चल रहे हैं वह यह है कि कोई कार्यक्षमता नहीं है जो आपको सरणी तत्व के अस्तित्व के आधार पर दो अलग-अलग अपडेट करने की अनुमति देती है। आपके केवल दो विकल्प हैं:

  1. आइटम ढूंढें, प्रासंगिक संपत्तियों के अस्तित्व को निर्धारित करें, अपने नए या परिवर्तन गुणों के साथ एक उचित अद्यतन संकलित करें और इसे निष्पादित करें। यह महत्वपूर्ण नकारात्मक पक्ष के साथ आता है कि यह एक समवर्ती सुरक्षित विधि नहीं है। दूसरे शब्दों में, यदि दो वेब सेवाओं का प्रयास इस पर किया जाता है तो एक दूसरे के परिवर्तनों को ओवरराइट कर सकता है।
  2. एम्बेडेड के बजाय विजेट गुण शीर्ष स्तर के दस्तावेज़ बनाएं। आप जो चाहते हैं उसे करने के लिए अप्सर्ट का उपयोग करने की अनुमति देता है। स्पष्ट नकारात्मक यह है कि स्कीमा डिजाइन के मामले में यह एक बहुत अच्छा विकल्प नहीं है। उदाहरण के लिए, यदि आप विजेट लाते हैं तो आपको स्वचालित रूप से सभी गुण नहीं मिलेंगे।
+0

मैं भी इस निष्कर्ष पर आया था। मेरे पास प्रति विजेट लगभग 3500 गुण हैं, और 100,000 से अधिक विजेट्स की संभावना है। क्या यह अपने स्वयं के संग्रह में संपत्ति रखने के लिए एक समझदार डिजाइन है? – justacodemonkey

+0

"अप्सर्ट" संभव है यदि आप अपने दस्तावेज़ को पुन: व्यवस्थित कर सकते हैं। मेरा जवाब देखें –

1

कम से कम PHP में यह मेरे लिए काम करता है, अपनी भाषा में अपनाने का प्रयास करें। आप की जरूरत है अपने संग्रह देखने के लिए की तरह:

 {Name: x, Properties: {name1:value1, name2:value2, name3:value3}} 

     foreach ($Properties as $name => $value) 
     { 
      $propertiesArray["Properties.$name"] = $value;     
     } 

     $criteria = array('Name' => $name); 
     $operation = array('$set' => $propertiesArray); 
     $options = array('upsert' => true); 

     $collection = $this->_dbh->selectCollection('Widget'); 
     $collection->update($criteria, $operation, $options); 

यह नए नाम सम्मिलित करता है, तो मौजूद हैं और अद्यतन करता है न कि उन जो पहले से ही वहाँ

+0

यह सही है लेकिन आपने वास्तव में यह नहीं बताया कि यह क्यों काम करता है। पूछताछकर्ता को सरणी के बजाय ऑब्जेक्ट का उपयोग करने के लिए अपने दस्तावेज़ को पुन: स्थापित करने की आवश्यकता है। अधिक जानकारी के लिए मेरा जवाब देखें। (इसके अलावा, अपरिपक्व ध्वज का उपयोग पूरे दस्तावेज़ को अपरिवर्तित करेगा, लेकिन सवाल विशेष रूप से सरणी तत्वों के बारे में था।) –

4

आप नहीं atomically Upsert सरणी तत्व कर सकते हैं। लेकिन यदि आप किसी दस्तावेज़ के बजाय ऑब्जेक्ट का उपयोग करने के लिए अपने दस्तावेज़ को पुन: व्यवस्थित कर सकते हैं, तो यह परमाणु रूप से संभव है। अपने संकेतन का उपयोग करना, संरचना होगा

Widget (collection) 
    --Name 
    --Properties 
    --Property1 
    --Property2 
     . 
     : 

एक उदाहरण दस्तावेज़ होगा

{ 
    name: 'widget-1', 
    properties: { 
     'property-1': 100, 
     'property-2': 200 
    } 
} 

एक आइटम 'संपत्ति-3' मूल्य 300 के साथ नामित किया गया Upsert करने के लिए, तुम क्या चाहते हैं

db.widgets.update(
    { name: 'widget-1' }, 
    { $set: { 'properties.property-3': 300 } } 
) 

एक दोष यह है कि फ़ील्ड नामों के लिए पूछताछ ($exists क्वेरी ऑपरेटर का उपयोग करके) स्कैनिंग की आवश्यकता होती है। आप एक अतिरिक्त सरणी फ़ील्ड जोड़कर इसे प्राप्त कर सकते हैं जो संपत्ति के नाम संग्रहीत करता है। इस क्षेत्र को अनुक्रमित किया जा सकता है और सामान्य रूप से पूछताछ की जा सकती है।Upserts बन

db.widgets.update(
    { name: 'widget-1' }, 
    { 
     $set: { 'properties.property-3': 300 }, 
     $addToSet: { propertyNames: 'property-3' } 
    } 
) 

जब एक संपत्ति को दूर करने के लिए, आप के रूप में अच्छी सरणी से यह खींच (मन $addToSet रखें हे (एन)। है)।

db.widgets.update(
    { name: 'widget-1' }, 
    { 
     $unset: { 'properties.property-3': true }, 
     $pull: { propertyNames: 'property-3' } 
    } 
) 
संबंधित मुद्दे