2012-01-13 12 views
11

का उपयोग करते समय mongodb में अप्सर्ट्स यदि यह मौजूद नहीं है तो मुझे दस्तावेज़ डालने की आवश्यकता है। मुझे पता है कि "अपरर्ट" विकल्प ऐसा कर सकता है, लेकिन मेरे पास कुछ विशेष ज़रूरत है।कस्टम _id मान

सबसे पहले मुझे केवल अपने _id फ़ील्ड के साथ दस्तावेज़ बनाने की आवश्यकता है, लेकिन केवल तभी यदि यह पहले से मौजूद नहीं है। मेरा _id फ़ील्ड मेरे द्वारा उत्पन्न एक संख्या है (ऑब्जेक्टआईडी नहीं)। अगर मैं फिर "Upsert" विकल्प का उपयोग मैं "मॉड _ id पर अनुमति नहीं"

db.mycollection.update({ _id: id }, { _id: id }, { upsert: true }); 

मुझे पता है कि हम एक $ सेट में _ id का उपयोग नहीं कर सकते हैं।

तो, मेरा सवाल यह है: यदि मोंगोड में परमाणु रूप से "बनाना अगर मौजूद नहीं है" का कोई तरीका है?

संपादित करें: @Barrie द्वारा प्रस्तावित के रूप में यह (NodeJS और नेवला का प्रयोग करके) काम करता है:

var newUser = new User({ _id: id }); 
newUser.save(function (err) {    
    if (err && err.code === 11000) {    
      console.log('If duplicate key the user already exists', newTwitterUser); 
     return; 
    } 
    console.log('New user or err', newTwitterUser); 
}); 

लेकिन मैं अभी भी अगर यह यह करने के लिए सबसे अच्छा तरीका है आश्चर्य है।

+0

'सेव' ऑपरेशन का उपयोग करने का प्रयास करें? i.e. db.collection.save ({"_ id": your_id}) –

+0

सहेजें डुप्लिकेट कुंजी त्रुटि के साथ विफल रहता है यदि पहले से मौजूद है – aartiles

उत्तर

5

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

+0

समझ में आता है, मैं इसे आजमा रहा हूं। – aartiles

+2

यह अभी भी दौड़ की स्थिति को संभाल नहीं करता है जहां दस्तावेज़ सम्मिलित होने के बाद और बाद के अपडेट से पहले हटा दिया जाता है। – Lucian

22

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

db.mycollection.update({ _id: id }, {$set: { _id: id, name: 'name' }}, { upsert: true }); 

बजाय इसका उपयोग:

db.mycollection.update({ _id: id }, {$set: { name: 'name' }}, { upsert: true }); 

यह बेहतर है क्योंकि यह दोनों डालने और अद्यतन के लिए काम करता है।

+1

क्या यह एक _id के साथ काम करता है जो कि ऑब्जेक्ट आईडी नहीं है, जैसा कि प्रश्न में वर्णित है? –

+1

हां। यह त्रुटि '_id पर अनुमति नहीं है' या तो ऑब्जेक्ट आईडी या कस्टम मान के रूप में _id के साथ त्रुटि का कारण बनता है। तो आपको हमेशा '$ set' ऑब्जेक्ट से _id को हटाना होगा। –

+0

धन्यवाद, $ सेट ऑब्जेक्ट से _id को हटाने के लिए मेरे लिए काम करता है। – ATilara

3

अद्यतन: _id के साथ उपरोक्त $setOnInsert के बिना उपरोक्त किया जा सकता है, जैसा ऊपर @ बार्री द्वारा समझाया गया है।

चाल $setOnInsert:{_id:1} का उपयोग अपरर्ट के साथ करने के लिए है, इस तरह _id केवल तभी लिखा जाता है जब यह एक सम्मिलित होता है, और अपडेट के लिए कभी नहीं।

Only, there was a bug preventing this from working until v2.6 - मैंने अभी 2.4 पर कोशिश की है और यह काम नहीं कर रहा है।

मेरे द्वारा उपयोग किए जाने वाले वर्कअराउंड में एक अद्वितीय इंडेक्स वाला एक और आईडी फ़ील्ड है। उदाहरण के लिए। $setOnInsert:{myId:1}

+1

setOnInsert मेरे लिए काम करते हैं तो यह एक समस्या होगी। जबकि बैरी का जवाब, सीधे डालें अद्यतन कार्यों को नहीं करेगा; नाट बार का जवाब, _id द्वारा अद्यतन खोज मानदंड सीमित। मैं क्या करना चाहता हूं: db.coll.update ({a: 1, b: 2}, {$ set: {c: 3, d: 4}, $ setOnInsert: {_id: 'xxxx'}}, { अपरिपक्व: सच}) – vdonkey

0

कृपया ध्यान दें कि जब आप एक साधारण कुंजी => मूल्य वस्तु ($ सेट या अन्य नहीं) अपरिवर्तित करते हैं तो $ setOnInsert आसानी से काम नहीं करता है। मुझे इसका उपयोग करने की आवश्यकता है (PHP में):

public function update($criteria , $new_object, array $options = array()){ 
    // In 2.6, $setOnInsert with upsert == true work with _id field 
    if(isset($options['upsert']) && $options['upsert']){ 
     $firstKey = array_keys($new_object)[0]; 
     if(strpos($firstKey, '$')===0){ 
      $new_object['$setOnInsert']['_id'] = $this->getStringId(); 
     } 
     //Even, we need to check if the object exists 
     else if($this->findOne($criteria, ['_id'])===null){ 
      //In this case, we need to set the _id 
      $new_object['_id'] = $this->getStringId(); 
     } 

    } 
    return parent::update($criteria, $new_object, $options); 
} 
संबंधित मुद्दे