কীভাবে একটি মঙ্গোডিবি ডকুমেন্টের _id আপডেট করবেন?


129

আমি _idএকটি নথির একটি ক্ষেত্র আপডেট করতে চাই । আমি জানি এটি সত্যিই ভাল অভ্যাস নয়। তবে কিছু প্রযুক্তিগত কারণে আমার এটি আপডেট করা দরকার। আমি যদি এটি আপডেট করার চেষ্টা করি তবে আমি পেয়েছি:

> db.clients.update({ _id: ObjectId("123")}, { $set: { _id: ObjectId("456")}})

Performing an update on the path '_id' would modify the immutable field '_id'

এবং আপডেট করা হয় না। আমি কীভাবে এটি আপডেট করতে পারি?

উত্তর:


216

আপনি এটি আপডেট করতে পারবেন না। আপনাকে একটি নতুন ব্যবহার করে দস্তাবেজটি সংরক্ষণ করতে হবে _idএবং তারপরে পুরানো নথিটি সরিয়ে ফেলতে হবে।

// store the document in a variable
doc = db.clients.findOne({_id: ObjectId("4cc45467c55f4d2d2a000002")})

// set a new _id on the document
doc._id = ObjectId("4c8a331bda76c559ef000004")

// insert the document, using the new _id
db.clients.insert(doc)

// remove the document with the old _id
db.clients.remove({_id: ObjectId("4cc45467c55f4d2d2a000002")})

29
এই দস্তাবেজের কোনও ক্ষেত্রে যদি একটি অনন্য সূচক থাকে তবে এটির সাথে একটি মজাদার বিষয়টি উপস্থিত হয়। এই পরিস্থিতিতে আপনার উদাহরণটি ব্যর্থ হবে কারণ একটি অনন্য সূচিযুক্ত ক্ষেত্রে নথির সাথে নথিকে সন্নিবেশ করা যায় না। আপনি প্রথমে মুছে ফেলা করে এটি ঠিক করতে পারেন, তবে এটি একটি খারাপ ধারণা কারণ যদি আপনার সন্নিবেশ কোনও কারণে ব্যর্থ হয় তবে আপনার ডেটা এখন হারিয়ে যায়। পরিবর্তে আপনাকে অবশ্যই আপনার সূচকটি ফেলে দিতে হবে, কাজটি সম্পাদন করতে হবে, তারপরে সূচকটি পুনরুদ্ধার করতে হবে।
স্কেললি

ভাল পয়েন্ট @ স্কেল্লি! আমি একই ধরণের সমস্যাগুলি নিয়ে ভাবতে দেখেছি এবং মাত্র ২ ঘন্টা আগে আপনার নতুন মন্তব্যটি দেখেছি। সুতরাং এই সংশোধনকারী আইডি ঝামেলা ব্যবহারকারীকে আইডি চয়ন করার অনুমতি দেওয়ার কারণে অন্তর্নিহিত সমস্যা হিসাবে বিবেচিত হয়?
রায়লুও

1
আপনি যদি একটি পেলে duplicate key errorমধ্যে insertলাইন এবং সমস্যা @skelly উল্লিখিত সম্পর্কে চিন্তিত হয় না, সবচেয়ে সহজ সমাধান শুধু কল হয় removeপ্রথম লাইন এবং তারপর কল insertলাইন। docইতিমধ্যে আপনার পর্দায় মুদ্রিত উচিত তাই এটি পুনরুদ্ধার করতে, সবচেয়ে খারাপ ক্ষেত্রে, এমনকি যদি সন্নিবেশ ব্যর্থ হয়, সহজ নথি জন্য সহজ হতে চাই।
ফিলফ্রেও

পরামিতি হিসাবে স্ট্রিং ছাড়াই কেবল অবজেক্টআইডি () ব্যবহার করা একটি নতুন অনন্য তৈরি করবে।
এরিক

1
@ শঙ্খদীপঘোষাল হ্যাঁ এটি একটি ঝুঁকিপূর্ণ, বিশেষত যদি আপনি কোনও লাইভ উত্পাদন ব্যবস্থার বিরুদ্ধে এটি সম্পাদন করছেন। দুর্ভাগ্যক্রমে আমি মনে করি যে আপনার সর্বোত্তম বিকল্পটি একটি নির্ধারিত আউটেজ নেওয়া এবং এই প্রক্রিয়া চলাকালীন সমস্ত লেখককে থামিয়ে দেওয়া। কিছুটা কম বেদনাদায়ক হতে পারে এমন আরেকটি বিকল্প হ'ল অ্যাপ্লিকেশনগুলিকে অস্থায়ীভাবে পঠনযোগ্য মোডে বাধ্য করা। সমস্ত অ্যাপ্লিকেশনগুলিতে পুনরায় কনফিগার করুন যা কেবলমাত্র একটি গৌণ নোডের দিকে নির্দেশ করে টোট তিনি ডিবি লেখেন। পাঠগুলি সফল হবে তবে লেখকগণ এই সময়ে ব্যর্থ হবে এবং আপনার ডিবি স্থির থাকবে।
skelly

32

আপনার পুরো সংগ্রহের জন্য এটি করতে আপনি একটি লুপও ব্যবহার করতে পারেন (নীল উদাহরণের ভিত্তিতে):

db.status.find().forEach(function(doc){ 
    doc._id=doc.UserId; db.status_new.insert(doc);
});
db.status_new.renameCollection("status", true);

এক্ষেত্রে ইউজারআইডি নতুন আইডিটি আমি ব্যবহার করতে চাইছিলাম


1
অনুসন্ধানে কোনও স্ন্যাপশট () কীভাবে দুর্ঘটনাবশত নতুন ডকগুলি পুনরাবৃত্ত হওয়ার সাথে সাথেই বাছাই করার পরামর্শ দেবে?
জন ফ্লিনচবগ 21

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

স্ন্যাপশটের বিকল্পের জন্য স্ট্যাকওভারফ্লো.com/a/28083980/305324 দেখুন । list()যৌক্তিক এটি, তবে বড় ডাটাবেসের জন্য এটি স্মৃতিশক্তি ছাড়িয়ে যেতে পারে
প্যাট্রিক

4
আহা, এর ১১ টি উপাখ্যান রয়েছে তবে কেউ বলেছে এটি অসীম লুপ? এখানে কি চুক্তি?
অ্যান্ড্রু

4
@ অ্যান্ড্রু কারণ সমসাময়িক পপ-কোডার সংস্কৃতি নির্দেশ করে যে ইনপুট আসলে কাজ করে তা যাচাই করার আগে আপনাকে সর্বদা ভাল ইনপুটটি স্বীকৃতি দেওয়া উচিত।
csvan

5

যদি আপনি একই সংগ্রহে _id এর নাম পরিবর্তন করতে চান (উদাহরণস্বরূপ, আপনি যদি কিছু _ID উপস্থাপন করতে চান):

db.someCollection.find().snapshot().forEach(function(doc) { 
   if (doc._id.indexOf("2019:") != 0) {
       print("Processing: " + doc._id);
       var oldDocId = doc._id;
       doc._id = "2019:" + doc._id; 
       db.someCollection.insert(doc);
       db.someCollection.remove({_id: oldDocId});
   }
});

যদি (doc._id.indexOf ("2019:")! = 0) {... অসীম লুপ প্রতিরোধের জন্য প্রয়োজন, যেহেতু forEach সন্নিবেশ করা ডক্সগুলি এমনকি, .Snapshot () পদ্ধতি ব্যবহার করে p


find(...).snapshot is not a functionতবে এটি বাদে দুর্দান্ত সমাধান। এছাড়াও, আপনি যদি _idনিজের কাস্টম আইডিটি প্রতিস্থাপন করতে চান তবে আপনি doc._id.toString().length === 24অসীম লুপটি আটকাতে পারেন কিনা তা পরীক্ষা করে দেখতে পারেন (ধরে নিলে আপনার কাস্টম আইডিগুলি 24 অক্ষর দীর্ঘ নয় ),
ড্যান ড্যাসক্লেস্কু

1

এখানে আমার কাছে এমন একটি সমাধান রয়েছে যা লুপ এবং পুরানো নথি অপসারণের জন্য একাধিক অনুরোধগুলি এড়ায়।

আপনি সহজেই এমন কোনও কিছু ব্যবহার করে ম্যানুয়ালি একটি নতুন ধারণা তৈরি করতে পারেন: _id:ObjectId() তবে মোংগো জেনে যাওয়া স্বয়ংক্রিয়ভাবে একটি _আইডির অনুপস্থিত হবে যদি আপনি অনুপস্থিত থাকেন তবে আপনি $projectআপনার নথির সমস্ত ক্ষেত্র সমেত একটি সংগ্রহ তৈরি করতে পারেন তবে ক্ষেত্রটি _id বাদ দিতে পারেন। তারপরে আপনি এটি দিয়ে সংরক্ষণ করতে পারেন$out

সুতরাং যদি আপনার নথিটি হয়:

{
"_id":ObjectId("5b5ed345cfbce6787588e480"),
"title": "foo",
"description": "bar"
}

তারপরে আপনার প্রশ্নটি হবে:

    db.getCollection('myCollection').aggregate([
        {$match:
             {_id: ObjectId("5b5ed345cfbce6787588e480")}
        }        
        {$project:
            {
             title: '$title',
             description: '$description'             
            }     
        },
        {$out: 'myCollection'}
    ])

আকর্ষণীয় ধারণা ... তবে আপনি সাধারণত _idমঙ্গোডিবিকে আর একটি তৈরি করতে না দিয়ে একটি নির্দিষ্ট মানকে সেট করতে চান ।
ড্যান ড্যাসক্লেস্কু

0

আপনি মংগোডিবি কম্পাস বা কমান্ড ব্যবহার করে একটি নতুন দস্তাবেজও তৈরি করতে পারেন এবং specific _idআপনার যে মানটি চান সেট করতে পারেন।

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