মঙ্গডব: উপস্থিত না থাকলে সন্নিবেশ করুন


146

প্রতিদিন, আমি দস্তাবেজের একটি স্টক (একটি আপডেট) পাই। আমি যা করতে চাই তা হ'ল প্রতিটি আইটেম alreadyোকানো যা ইতিমধ্যে বিদ্যমান নেই।

  • আমি প্রথমবার এগুলি sertedোকানোর সময় এবং সর্বশেষবার যখন তাদের একটি আপডেটে দেখেছিলাম তখনও আমি তার নজর রাখতে চাই।
  • আমি নকল নথি থাকতে চাই না।
  • আমি পূর্বে সংরক্ষিত কোনও দস্তাবেজ সরাতে চাই না, তবে আমার আপডেটে নেই।
  • 95% (আনুমানিক) রেকর্ডগুলি দিনে দিনে অশোধিত হয়।

আমি পাইথন ড্রাইভার (পাইমোঙ্গো) ব্যবহার করছি।

আমি বর্তমানে যা করছি তা হ'ল (সিউডো-কোড):

for each document in update:
      existing_document = collection.find_one(document)
      if not existing_document:
           document['insertion_date'] = now
      else:
           document = existing_document
      document['last_update_date'] = now
      my_collection.save(document)

আমার সমস্যাটি হ'ল এটি খুব ধীর (100 000 রেকর্ডেরও কম রেকর্ডের জন্য 40 মিনিট, এবং আপডেটে আমার মিলিয়ন রয়েছে)। আমি নিশ্চিত যে এটি করার জন্য কিছু অন্তর্নির্মিত আছে তবে আপডেটের জন্য নথিটি এমএমএমএইচ .... কিছুটা পরিশ্রমী .... ( http://www.mongodb.org/display/DOCS/Updating )

কেউ কীভাবে দ্রুত এটি করতে পরামর্শ দিতে পারেন?

উত্তর:


153

আপনি একটি "আপসার্ট" করতে চান এমন মনে হচ্ছে। মঙ্গোডিবি এর জন্য অন্তর্নির্মিত সমর্থন করেছে। আপনার আপডেট () কলটিতে একটি অতিরিক্ত প্যারামিটার পাস করুন: sert উপস্থাপনা: সত্য} উদাহরণ স্বরূপ:

key = {'key':'value'}
data = {'key2':'value2', 'key3':'value3'};
coll.update(key, data, upsert=True); #In python upsert must be passed as a keyword argument

এটি আপনার if-সন্ধান-অন্য-আপডেট ব্লকটিকে পুরোপুরি প্রতিস্থাপন করে। কীটি উপস্থিত না থাকলে এটি সন্নিবেশ করবে এবং এটি উপস্থিত থাকলে আপডেট হবে।

আগে:

{"key":"value", "key2":"Ohai."}

পরে:

{"key":"value", "key2":"value2", "key3":"value3"}

আপনি কোন ডেটা লিখতে চান তাও নির্দিষ্ট করে দিতে পারেন:

data = {"$set":{"key2":"value2"}}

এখন আপনার নির্বাচিত দস্তাবেজটি কেবল "কী 2" এর মান আপডেট করবে এবং অন্য সব কিছুই অদৃশ্য রাখবে।


5
এটাই তো আমি চাই! যদি অবজেক্টটি ইতিমধ্যে উপস্থিত থাকে তবে আমি কীভাবে সন্নিবেশ_সামগ্রীটিকে স্পর্শ করতে পারি না?
লেমিজ ২

24
আপনি কি দয়া করে প্রথম sertোকাতে একটি ক্ষেত্র স্থাপনের উদাহরণ দিতে পারেন এবং উপস্থিত থাকলে তা আপডেট করবেন না? @ ভ্যানগুইয়েন
আলী শাকিবা

7
আপনার উত্তরের প্রথম অংশটি ভুল, আমার ধারণা। coll.update ডেটা প্রতিস্থাপন করবে যদি না আপনি $ সেট ব্যবহার করেন। সুতরাং পরে আসলে হবে: {'কী 2': 'মান 2', 'কী 3': 'মান 3'}
জেমস ব্ল্যাকবার্ন

9
-1 এই উত্তর বিপজ্জনক। আপনি "কী" এর মান অনুসারে সন্ধান করেন এবং তারপরে আপনি "কী" মুছবেন, যাতে পরবর্তীকালে আপনি এটি আর খুঁজে পেতে সক্ষম হবেন না। এটি খুব সম্ভবত ব্যবহারের কেস।
মার্ক ই হাজেস

23
আপনার should setOnInsert অপারেটর ব্যবহার করা উচিত! প্রশ্নটি পাওয়া গেলে আপসেট এমনকি নথিকে আপডেট করবে।
ইউলচেেনি

63

মঙ্গোডিবি ২.৪ থেকে আপনি you setOnInsert ( http://docs.mongodb.org/manual/references/operator/setOnInsert/ ) ব্যবহার করতে পারেন

আপনার আপসার্ট কমান্ডে $ setOnInsert এবং 'last_update_date' ব্যবহার করে 'insertion_date' সেট করুন।

আপনার সিউডোকোডকে একটি কার্যকারী উদাহরণে পরিণত করতে:

now = datetime.utcnow()
for document in update:
    collection.update_one(
        {"_id": document["_id"]},
        {
            "$setOnInsert": {"insertion_date": now},
            "$set": {"last_update_date": now},
        },
        upsert=True,
    )

3
এটি সঠিক, আপনি একটি ফিল্টারের সাথে মিলে যাওয়া কোনও দস্তাবেজ পরীক্ষা করতে পারেন এবং $ setOnInsert ব্যবহার করে কিছু না পাওয়া গেলে sertোকাতে পারেন। নোট করুন যে সেখানে একটি বাগ ছিল যেখানে আপনি _id ক্ষেত্রের সাথে $ setOnInsert করতে পারবেন না - এটি এমন কিছু বলবে যে "মোড দ্য _আইডি ফিল্ডটি করতে পারে না"। এটি একটি বাগ ছিল, যা v2.5.4 এ স্থির হয়েছে বা সেখানে অলস রয়েছে। আপনি যদি এই বার্তা বা ইস্যুটি দেখতে পান তবে কেবল সর্বশেষতম সংস্করণটি পান।
কাইরেন জনস্টোন

19

আপনি সর্বদা একটি অনন্য সূচক তৈরি করতে পারেন, যা মঙ্গোডিবি বিরোধী সংরক্ষণকে প্রত্যাখ্যান করে। মংডোব শেল ব্যবহার করে নিম্নলিখিত করা বিবেচনা করুন:

> db.getCollection("test").insert ({a:1, b:2, c:3})
> db.getCollection("test").find()
{ "_id" : ObjectId("50c8e35adde18a44f284e7ac"), "a" : 1, "b" : 2, "c" : 3 }
> db.getCollection("test").ensureIndex ({"a" : 1}, {unique: true})
> db.getCollection("test").insert({a:2, b:12, c:13})      # This works
> db.getCollection("test").insert({a:1, b:12, c:13})      # This fails
E11000 duplicate key error index: foo.test.$a_1  dup key: { : 1.0 }

12

আপনি sert setOnInsert অপারেটর সহ উপগ্রহ ব্যবহার করতে পারেন।

db.Table.update({noExist: true}, {"$setOnInsert": {xxxYourDocumentxxx}}, {upsert: true})


11
পিমোঙ্গো নিয়ে যে কেউ জিজ্ঞাসা করছেন তাদের জন্য তৃতীয় প্যারামটি ঠিক সত্য হতে হবে বা একটি ডিক্ট নয়
এস ..

6

1. আপডেট ব্যবহার করুন।

উপরের ভ্যান এনগুইনের উত্তর থেকে অঙ্কন, সংরক্ষণের পরিবর্তে আপডেট ব্যবহার করুন। এটি আপনাকে আপসার্ট বিকল্পটিতে অ্যাক্সেস দেয়।

দ্রষ্টব্য : পাওয়া গেলে এই পদ্ধতিটি পুরো দস্তাবেজকে ওভাররাইড করে ( ডক্স থেকে )

var conditions = { name: 'borne' }   , update = { $inc: { visits: 1 }} , options = { multi: true };

Model.update(conditions, update, options, callback);

function callback (err, numAffected) {   // numAffected is the number of updated documents })

1.a. সেট Use সেট ব্যবহার করুন

আপনি যদি নথির একটি নির্বাচন আপডেট করতে চান তবে পুরো জিনিসটি না, আপনি আপডেট সহ $ সেট পদ্ধতিটি ব্যবহার করতে পারেন। (আবার, ডক্স থেকে ) ... সুতরাং, আপনি যদি সেট করতে চান ...

var query = { name: 'borne' };  Model.update(query, ***{ name: 'jason borne' }***, options, callback)

এটি প্রেরণ করুন ...

Model.update(query, ***{ $set: { name: 'jason borne' }}***, options, callback)

এটি দুর্ঘটনাক্রমে আপনার সমস্ত দস্তাবেজ (গুলি) ওভাররাইট করা রোধ করতে সহায়তা করে { name: 'jason borne' }


6

সারসংক্ষেপ

  • আপনার কাছে রেকর্ডের একটি বিদ্যমান সংগ্রহ রয়েছে।
  • আপনার কাছে একটি সেট রেকর্ড রয়েছে যা বিদ্যমান রেকর্ডগুলিতে আপডেট থাকে।
  • কিছু আপডেট সত্যই কিছু আপডেট করে না, তারা আপনার ইতিমধ্যে যা আছে তা নকল করে।
  • সমস্ত আপডেটের মধ্যে একই ক্ষেত্র রয়েছে যা ইতিমধ্যে রয়েছে, কেবলমাত্র পৃথক মান রয়েছে।
  • আপনি যখন রেকর্ডটি সর্বশেষ পরিবর্তন হয়েছিল সেখানে ট্র্যাক করতে চান, যেখানে একটি মান আসলে পরিবর্তিত হয়েছিল।

দ্রষ্টব্য, আমি পাইমঙ্গো অনুমান করছি, আপনার পছন্দের ভাষা অনুসারে পরিবর্তন করুন।

নির্দেশাবলী:

  1. অনন্য = সত্য সহ একটি সূচক দিয়ে সংগ্রহ তৈরি করুন যাতে আপনি সদৃশ রেকর্ড না পান।

  2. আপনার ইনপুট রেকর্ডগুলিতে আইট্রেট করুন, তাদের মধ্যে 15,000 রেকর্ড বা তার বেশি ব্যাচ তৈরি করুন। ব্যাচের প্রতিটি রেকর্ডের জন্য, আপনি যে তথ্যটি সন্নিবেশ করতে চান তা সমন্বিত একটি ডিক তৈরি করুন, ধরে নেবেন যে প্রত্যেকটি একটি নতুন রেকর্ড হতে চলেছে। এগুলিতে 'তৈরি' এবং 'আপডেট' টাইমস্ট্যাম্প যুক্ত করুন। এটিকে 'ContinOnError' পতাকা = সত্য সহ একটি ব্যাচ সন্নিবেশ কমান্ড হিসাবে ইস্যু করুন, সুতরাং সেখানে ডুপ্লিকেট কী রয়েছে এমন কিছুর পরেও (যা মনে হবে সেখানে থাকবে) অন্য কিছুর সন্নিবেশ ঘটবে। এটি খুব দ্রুত ঘটবে। বাল্ক সন্নিবেশ করে, আমি 15k / সেকেন্ডের পারফরম্যান্স স্তর পেয়েছি। ContinOnError এ আরও নোট, দেখুন http://docs.mongodb.org/manual/core/write-operations/

    রেকর্ড সন্নিবেশগুলি খুব দ্রুত ঘটে, তাই আপনার অল্প সময়ের মধ্যে inোকানোগুলি সম্পন্ন করা হবে। এখন, এটি সম্পর্কিত রেকর্ড আপডেট করার সময় এসেছে। ব্যাচের পুনরুদ্ধারের সাথে এটি করুন, একবারে একের চেয়ে অনেক দ্রুত।

  3. আপনার সমস্ত ইনপুট রেকর্ডগুলিতে আবার আইট্রেট করুন, 15 কে বা আরও বেশি কিছু ব্যাচ তৈরি করুন। কীগুলি বের করুন (এক কী থাকলে সর্বোত্তম, তবে সেখানে না থাকলে সহায়তা করা যায় না)। মোংগো থেকে একটি ডিবি.কোলেশননামব্লাহ.ফাইন্ড ({ক্ষেত্র: {$ ইন: [1, 2,3 ...}) ক্যোয়ারী সহ এই গুচ্ছ রেকর্ডগুলি পুনরুদ্ধার করুন। এই প্রতিটি রেকর্ডের জন্য, কোনও আপডেট আছে কিনা তা নির্ধারণ করুন এবং যদি তাই হয় তবে 'আপডেট' টাইমস্ট্যাম্পটি আপডেট করে আপডেট আপডেট করুন issue

    দুর্ভাগ্যক্রমে, আমাদের লক্ষ করা উচিত, মঙ্গোডিবি ২.৪ এবং এর নীচে বাল্ক আপডেট অপারেশন অন্তর্ভুক্ত নয়। তারা যে কাজ করছে।

কী অপ্টিমাইজেশন পয়েন্ট:

  • সন্নিবেশগুলি বিপুল পরিমাণে আপনার ক্রিয়াকলাপকে ত্বরান্বিত করবে।
  • ম্যাসেজ ও রেকর্ডগুলি পুনরুদ্ধার করা জিনিসগুলিও গতি বাড়িয়ে তুলবে।
  • ব্যক্তিগত আপডেটগুলি এখন একমাত্র সম্ভাব্য রুট, তবে 10 জেন এতে কাজ করছে। সম্ভবত, এটি ২.6-এ হবে, যদিও আমি নিশ্চিত নই যে এটি ততক্ষণে শেষ হবে কিনা, অনেক কিছুই করার আছে (আমি তাদের জিরা সিস্টেমটি অনুসরণ করছি)।

5

আমি মনে করি না মংডোব এই ধরণের নির্বাচনী সংরক্ষণকে সমর্থন করে। আমার লেমিজের মতো একই সমস্যা রয়েছে এবং 'তৈরি' এবং 'আপডেটেড' টাইমস্ট্যাম্প উভয়ের সাথে কাজ করার সময় আপডেট (মানদণ্ড, নিউওবিজে, উপগ্রহ, মাল্টি) সঠিকভাবে কাজ করে না। নিম্নলিখিত উত্সাহ বিবৃতি দেওয়া:

update( { "name": "abc" }, 
        { $set: { "created": "2010-07-14 11:11:11", 
                  "updated": "2010-07-14 11:11:11" }},
        true, true ) 

পরিস্থিতি # 1 - 'এবিসি' এর 'নাম' সহ নথিটি বিদ্যমান নেই: নতুন দস্তাবেজ 'নাম' = 'অ্যাবসি', 'তৈরি' = 2010-07-14 11:11:11, এবং 'আপডেট' = দিয়ে তৈরি করা হয়েছে 2010-07-14 11:11:11।

পরিস্থিতি # 2 - 'এবিসি' এর 'নাম' সহ নথিটি ইতিমধ্যে নিম্নলিখিতগুলির সাথে উপস্থিত রয়েছে: 'নাম' = 'এবিসি', 'তৈরি' = 2010-07-12 09:09:09, এবং 'আপডেট' = 2010-07 -13 10:10:10। উত্থাপনের পরে, নথিটি এখন # 1 দৃশ্যের ফলাফলের মতো হবে। কোন ক্ষেত্র সন্নিবেশ করানো হলে সেট করা হবে এবং আপডেট করা হলে কোন ক্ষেত্রটি একা থাকবে left

আমার সমাধানটি ছিল ক্রাইটেরার ক্ষেত্রগুলিতে একটি অনন্য সূচক তৈরি করা , একটি সন্নিবেশ করানো এবং তত্ক্ষণাত্ 'আপডেটড' ক্ষেত্রটিতে একটি আপডেট সম্পাদন করা।


4

সাধারণভাবে, আপডেট ব্যবহার মঙ্গোডিবিতে আরও ভাল কারণ এটি নথিটি এখনও উপস্থিত না থাকলে এটি তৈরি করবে যদিও আপনার পাইথন অ্যাডাপ্টারের সাহায্যে এটি কীভাবে কাজ করবেন তা সম্পর্কে আমি নিশ্চিত নই।

দ্বিতীয়ত, যদি কেবলমাত্র সেই নথির অস্তিত্ব আছে কিনা তা আপনার জানা দরকার তবে গণনা () যা কেবলমাত্র একটি সংখ্যার প্রত্যাশা করে তা অন্বেষণের কারণে আপনার মঙ্গোডিবি থেকে পুরো ডকুমেন্টটি স্থানান্তর করে এমন ফাইন্ড_-এর চেয়ে ভাল বিকল্প হবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.