MongoDB परमाणु "findOrCreate": findOne, सम्मिलित करें यदि कोई नहीं, लेकिन अपडेट न करें


114

जैसा कि शीर्षक कहता है, मैं _id द्वारा एक दस्तावेज़ के लिए एक खोज (एक) करना चाहता हूं, और यदि मौजूद नहीं है, तो इसे बनाया है, फिर चाहे वह मिला या बनाया गया था, क्या यह कॉलबैक में वापस आ गया है।

मैं इसे अद्यतन नहीं करना चाहता अगर यह मौजूद है, जैसा कि मैंने पढ़ा है aAndModify करता है। मैंने इस बारे में Stackoverflow पर कई अन्य प्रश्न देखे हैं, लेकिन फिर से, कुछ भी अपडेट नहीं करना चाहते हैं।

मैं अनिश्चित हूँ अगर (मौजूदा नहीं) बनाने से, वास्तव में अद्यतन हर किसी के बारे में बात कर रहा है, यह सब इतना उलझन में है ...

जवाबों:


192

MongoDB 2.4 के साथ शुरुआत करते हुए, परमाणु findOrCreateजैसे संचालन के लिए एक अद्वितीय सूचकांक (या किसी भी अन्य समाधान) पर भरोसा करना अब आवश्यक नहीं है ।

यह करने के लिए धन्यवाद है ऑपरेटर 2.4 के लिए नया है, जो आप अद्यतन जो केवल होना चाहिए जब दस्तावेज़ डालने निर्दिष्ट करने के लिए अनुमति देता है।$setOnInsert

यह, upsertविकल्प के साथ संयुक्त है , इसका मतलब है कि आप findAndModifyएक परमाणु findOrCreate-जैसे ऑपरेशन को प्राप्त करने के लिए उपयोग कर सकते हैं ।

db.collection.findAndModify({
  query: { _id: "some potentially existing id" },
  update: {
    $setOnInsert: { foo: "bar" }
  },
  new: true,   // return new doc if one is upserted
  upsert: true // insert the document if it does not exist
})

जैसा कि $setOnInsertकेवल डाले जा रहे दस्तावेजों को प्रभावित करता है, यदि कोई मौजूदा दस्तावेज़ पाया जाता है, तो कोई संशोधन नहीं होगा। यदि कोई दस्तावेज़ मौजूद नहीं है, तो यह निर्दिष्ट _id के साथ एक को बनाए रखेगा, फिर केवल सेट सम्मिलित करें। दोनों मामलों में, दस्तावेज़ वापस कर दिया जाता है।


3
@ यदि आप नोड के लिए मेनगोडब मूल चालक का उपयोग कर रहे हैं तो वाक्य रचना अधिक पसंद होगी collection.findAndModify({_id:'theId'}, <your sort opts>, {$setOnInsert:{foo: 'bar'}}, {new:true, upsert:true}, callback)। देखें डॉक्स
numbers1311407

7
क्या यह जानने का कोई तरीका है कि दस्तावेज़ को अपडेट किया गया है या डाला गया है?
कयामत 23

3
यदि आप जांचना चाहते हैं कि क्या ऊपर दी गई क्वेरी ( db.collection.findAndModify({query: {_id: "some potentially existing id"}, update: {$setOnInsert: {foo: "bar"}}, new: true, upsert: true})) इंसर्ट ( दस्तावेज़ को सम्मिलित) एड करती है, तो आपको उपयोग करने पर विचार करना चाहिए db.collection.updateOne({_id: "some potentially existing id"}, {$setOnInsert: {foo: "bar"}}, {upsert: true})। यदि डॉक्टर पहले ही मौजूद है {"acknowledged": true, "matchedCount": 0, "modifiedCount": 0, "upsertedId": ObjectId("for newly inserted one")}तो यह वापस आ जाता {"acknowledged": true, "matchedCount": 1, "modifiedCount": 0}है।
Константин Ван

8
के स्वाद में पदावनत लगती है findOneAndUpdate, findOneAndReplaceयाfindOneAndDelete
रावशां समंदरोव

5
हालांकि यहां सावधानी बरतने की जरूरत है। यह केवल तभी काम करता है जब findAndModify / findOneAndUpdate / updateOne का चयनकर्ता विशिष्ट रूप से _id द्वारा एक दस्तावेज़ की पहचान करता है। अन्यथा सर्वर पर क्वेरी और अपडेट / इंसर्ट में अपग्रेड अलग हो जाता है। अद्यतन अभी भी परमाणु होगा। लेकिन क्वेरी और अपडेट को एक साथ एटोमिक रूप से निष्पादित नहीं किया जाएगा।
अपराह्न

15

चालक संस्करण> 2

नवीनतम ड्राइवर (> संस्करण 2) का उपयोग करते हुए , आप findAndModifyपदावनत के रूप में findOneAndUpdate का उपयोग करेंगे । नई विधि 3 तर्क लेती है,filter , updateवस्तु (जो अपने डिफ़ॉल्ट गुण होता है, कि एक नई वस्तु के लिए डाला जाना चाहिए), और optionsजहाँ आप Upsert आपरेशन निर्दिष्ट करना होगा।

वादे वाक्यविन्यास का उपयोग करते हुए, यह इस तरह दिखता है:

const result = await collection.findOneAndUpdate(
  { _id: new ObjectId(id) },
  {
    $setOnInsert: { foo: "bar" },
  },
  {
    returnOriginal: false,
    upsert: true,
  }
);

const newOrUpdatedDocument = result.value;

धन्यवाद, returnOriginalक्या returnNewDocumentमुझे सोचना चाहिए - docs.mongodb.com/manual/reference/method/…
डोमिनिक

कोई बात नहीं, नोड ड्राइवर ने इसे अलग तरीके से लागू किया और आपका उत्तर सही है
डोमिनिक

6

यह थोड़ा गंदा है, लेकिन आप इसे सम्मिलित कर सकते हैं।

सुनिश्चित करें कि कुंजी पर एक अद्वितीय सूचकांक है (यदि आप _id का उपयोग ठीक है, तो यह पहले से ही अद्वितीय है)।

इस तरह से यदि तत्व पहले से मौजूद है तो यह एक अपवाद लौटाएगा जिसे आप पकड़ सकते हैं।

यदि यह मौजूद नहीं है, तो नया दस्तावेज़ डाला जाएगा।

अपडेट किया गया: MongoDB प्रलेखन पर इस तकनीक का विस्तृत विवरण


ठीक है, एक अच्छा विचार है, लेकिन पहले से मौजूद मूल्य के लिए यह एक त्रुटि लौटाएगा, लेकिन मूल्य ही नहीं, है ना?
डिसिप्लिन

3
यह वास्तव में आपरेशन के अलग-थलग दृश्यों के लिए सिफारिश की समाधानों में से एक है (लगता है फिर अगर नहीं मिला, शायद बनाने) docs.mongodb.org/manual/tutorial/isolate-sequence-of-operations
numbers1311407

@ डिसिपोल यदि आप परमाणु संचालन का एक सेट करना चाहते हैं, तो आपको पहले दस्तावेज़ को लॉक करना चाहिए, फिर इसे संशोधित करना चाहिए, और अंत में इसे जारी करना चाहिए। इसके लिए अधिक प्रश्नों की आवश्यकता होगी, लेकिन आप सर्वोत्तम स्थिति परिदृश्य के लिए अनुकूलित कर सकते हैं और अधिकांश समय केवल 1-2 क्वेरी कर सकते हैं। देखें: docs.mongodb.org/manual/tutorial/perform-two-phase-commits
Madarco

1

यहाँ मैंने क्या किया (रूबी MongoDB ड्राइवर):

$db[:tags].update_one({:tag => 'flat'}, {'$set' => {:tag => 'earth' }}, { :upsert => true })}

यदि यह मौजूद है, तो यह इसे अपडेट कर देगा और अगर यह नहीं है तो इसे डालें।

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