আমি কীভাবে মংগোডিবিতে কোনও বস্তুকে আংশিক আপডেট করব যাতে নতুন অবজেক্টটি বিদ্যমানটির সাথে ওভারলে / মিশে যায়


181

এই নথিটি মঙ্গোবিবিতে সংরক্ষিত হয়েছে

{
   _id : ...,
   some_key: { 
        param1 : "val1",
        param2 : "val2",
        param3 : "val3"
   }
}

বাইরের বিশ্ব থেকে param2এবং নতুন তথ্য সম্বলিত কোনও বিষয়টিকে param3সংরক্ষণ করা দরকার

var new_info = {
    param2 : "val2_new",
    param3 : "val3_new"
};

আমি অবজেক্টের বিদ্যমান অবস্থার উপরে নতুন ক্ষেত্রগুলিকে একত্রীকরণ / ওভারলে করতে চাই যাতে প্যারাম 1 অপসারণ না হয়

এটা করছি

db.collection.update(  { _id:...} , { $set: { some_key : new_info  } } 

মঙ্গোডিবিতে নেতৃত্ব দেবে যেমন বলা হয়েছিল ঠিক তেমন করছে, এবং সেই মানটির জন্য কিছু_কে সেট করে। পুরানো এক প্রতিস্থাপন।

{
   _id : ...,
   some_key: { 
      param2 : "val2_new",
      param3 : "val3_new"
   }
}

মোঙ্গোডিবি কেবল নতুন ক্ষেত্রগুলি আপডেট করার উপায় কী (সেগুলিকে একের পর এক স্পষ্টভাবে উল্লেখ না করে)? এটি পেতে:

{
   _id : ...,
   some_key: { 
        param1 : "val1",
        param2 : "val2_new",
        param3 : "val3_new"
   }
}

আমি জাভা ক্লায়েন্ট ব্যবহার করছি, তবে কোনও উদাহরণ প্রশংসিত হবে


2
দয়া করে $ মার্জ ইস্যুটির জন্য ভোট দিন: jira.mongodb.org/browse/SERVER-21094
আলী

উত্তর:


105

যদি আমি প্রশ্নটি সঠিকভাবে বুঝতে পারি তবে আপনি অন্য দস্তাবেজের বিষয়বস্তু সহ একটি ডকুমেন্ট আপডেট করতে চান তবে কেবলমাত্র ক্ষেত্রগুলি যা ইতিমধ্যে উপস্থিত নেই এবং ইতিমধ্যে সেট করা ক্ষেত্রগুলি সম্পূর্ণ উপেক্ষা করে (অন্য কোনও মান হলেও)।

একক কমান্ডে এটি করার কোনও উপায় নেই।

আপনাকে প্রথমে ডকুমেন্টটি জিজ্ঞাসা করতে হবে, আপনি কী চান তা বের করতে হবে $setএবং তারপরে এটি আপডেট করতে হবে (পুরানো মানগুলি মিলের ফিল্টার হিসাবে ব্যবহার করে নিশ্চিত করা হবে যে আপনি মাঝে মধ্যে সমবর্তী আপডেটগুলি পান না)।


আপনার প্রশ্নের আরেকটি পাঠ্য হ'ল আপনি এতে খুশি $set, তবে সমস্ত ক্ষেত্র স্পষ্টভাবে সেট করতে চান না। আপনি কিভাবে তথ্য পাস করবেন?

আপনি জানেন যে আপনি নিম্নলিখিতগুলি করতে পারেন:

db.collection.update(  { _id:...} , { $set: someObjectWithNewData } 

আপনি যদি সমস্ত ক্ষেত্র নিঃশর্তভাবে সেট করতে চান তবে আপনি এই জাতীয় $ মাল্টি প্যারামিটার ব্যবহার করতে পারেন : db.collection.update( { _id:...} , { $set: someObjectWithNewData, { $multi: true } } )
গ্রামবাসী

12
কোনও $ মাল্টি প্যারামিটার নেই। একটি বহু বিকল্প রয়েছে (যা আপনি যা লিঙ্ক করেছেন), তবে ক্ষেত্রগুলি কীভাবে আপডেট করা হয় তা এটি প্রভাবিত করে না। আপনি কোনও একক দস্তাবেজ বা ক্যোয়ারী প্যারামিটারের সাথে মেলে এমন সমস্ত নথি আপডেট করে কিনা তা এটি নিয়ন্ত্রণ করে।
বব কার্নস

1
এটি যা কিছু তা বোঝায় না। মঙ্গো নিয়ে কাজ করার সময় এটিও পারমাণবিক ক্রিয়াকলাপগুলির আপডেটের জন্য পছন্দ হয়। প্রথমে এটি পড়া যখনই অন্য কেউ আপনার ডেটা পরিবর্তন করে তখন এটি নোংরা পড়ার কারণ হয়। এবং যেহেতু মঙ্গোর কোনও লেনদেন নেই, এটি আপনার জন্য ডেটা আনন্দের সাথে দূষিত করবে।
ব্যাঙবাড়ী

@ ফ্রিজিনেভিশন: আপনি পুরানো মানগুলিকে আপডেটের সাথে মিলে যাওয়া ফিল্টার হিসাবে ব্যবহার করে এটি পারমাণবিক করতে পারেন way এইভাবে, এর মধ্যে যদি কোনও বিরোধী সমবর্তী আপডেট হয় তবে আপনার আপডেট ব্যর্থ হবে। তারপরে আপনি এটি সনাক্ত করতে পারেন এবং সেই অনুসারে কাজ করতে পারেন। এটিকে আশাবাদী লকিং বলা হয়। তবে হ্যাঁ, এটি আপনার প্রয়োগ যথাযথভাবে প্রয়োগের উপর নির্ভর করে, মঙ্গোর স্বয়ং বিল্ট-ইন লেনদেন নেই have
থিলো

আমি মনে করি এটি জাভাস্ক্রিপ্টে দুটি বস্তু মার্জ করার আরও সাধারণ প্রশ্ন। IIRC ধারণা কেবল পুরানো নতুন বৈশিষ্ট্য দায়িত্ব অর্পণ করা হয়
information_interchange

110

আমি এটি আমার নিজের ফাংশন দিয়ে সমাধান করেছি। আপনি যদি নথিতে নির্দিষ্ট ক্ষেত্রটি আপডেট করতে চান তবে আপনাকে এটিকে স্পষ্টভাবে সম্বোধন করতে হবে।

উদাহরণ:

{
    _id : ...,
    some_key: { 
        param1 : "val1",
        param2 : "val2",
        param3 : "val3"
    }
}

আপনি যদি কেবল প্যারাম 2 আপডেট করতে চান তবে এটি করা ভুল:

db.collection.update(  { _id:...} , { $set: { some_key : new_info  } }  //WRONG

আপনি অবশ্যই ব্যবহার করুন:

db.collection.update(  { _id:...} , { $set: { some_key.param2 : new_info  } } 

সুতরাং আমি একটি ফাংশন কিছু লিখেছি:

function _update($id, $data, $options=array()){

    $temp = array();
    foreach($data as $key => $value)
    {
        $temp["some_key.".$key] = $value;
    } 

    $collection->update(
        array('_id' => $id),
        array('$set' => $temp)
    );

}

_update('1', array('param2' => 'some data'));

11
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। আরও ভাল ফ্ল্যাটেনবজ ফাংশনের জন্য gist.github.com/penguinboy/762197 দেখুন
steph643

ধন্যবাদ আপনার প্রতিক্রিয়া আমাকে গাইড করতে সহায়তা করেছে। আমি নিম্নলিখিত হিসাবে ব্যবহারকারীদের সংগ্রহে একটি ব্যবহারকারীর একটি নির্দিষ্ট কী এর মানটি সংশোধন করতে সক্ষম হয়েছি:db.users.update( { _id: ObjectId("594dbc3186bb5c84442949b1") }, { $set: { resume: { url: "http://i.imgur.com/UFX0yXs.jpg" } } } )
লুক স্কোয়েন

এই অপারেশনটি কি পারমাণবিক এবং বিচ্ছিন্ন? অর্থ, যদি 2 সমান্তরাল থ্রেডগুলি একই দস্তাবেজের 2 টি আলাদা ক্ষেত্র সেট করার চেষ্টা করে, তবে তা কি জাতি শর্ত এবং অনাকাঙ্ক্ষিত ফলাফলের ফলস্বরূপ
তাই এলোমেলো-বউ

21

আপনি objects অবজেক্টের অন্যান্য বৈশিষ্ট্যগুলিকে প্রভাবিত না করেই গভীরতর অবজেক্টগুলিতে ক্ষেত্রগুলি অ্যাক্সেস করতে এবং সেট করতে ডট-নোটেশন ব্যবহার করতে পারেন।

আপনি উপরে উল্লিখিত বস্তুটি দিয়েছেন:

> db.test.insert({"id": "test_object", "some_key": {"param1": "val1", "param2": "val2", "param3": "val3"}})
WriteResult({ "nInserted" : 1 })

আমরা ঠিক some_key.param2এবং some_key.param3:

> db.test.findAndModify({
... query: {"id": "test_object"},
... update: {"$set": {"some_key.param2": "val2_new", "some_key.param3": "val3_new"}},
... new: true
... })
{
    "_id" : ObjectId("56476e04e5f19d86ece5b81d"),
    "id" : "test_object",
    "some_key" : {
        "param1" : "val1",
        "param2" : "val2_new",
        "param3" : "val3_new"
    }
}

আপনি নিজের মতো গভীরভাবে ডেলিভ করতে পারেন। বিদ্যমান জিনিসগুলিকে প্রভাবিত না করে কোনও বস্তুতে নতুন বৈশিষ্ট্য যুক্ত করার জন্য এটি দরকারী।


আমি কি একটি নতুন কী যুক্ত করতে পারি ... যেমন "কিছু কী": {"প্যারাম 1": "ভাল 1", "প্যারাম 2": "ভাল 2_নেউ", "প্যারাম 3": "ভাল 3_নেউ", "প্যারাম 4": "ভাল 4_নিউ",}
উর্বশী সনি

17

সর্বোত্তম সমাধান হ'ল অবজেক্ট থেকে বৈশিষ্ট্য আহরণ এবং এগুলিকে ফ্ল্যাট ডট-নোটেশন কী-মান যুক্ত করুন। আপনি উদাহরণস্বরূপ এই গ্রন্থাগারটি ব্যবহার করতে পারেন:

https://www.npmjs.com/package/mongo-dot-notation

এটির .flattenকার্যকারিতা রয়েছে যা আপনাকে properties সেট সংশোধককে দেওয়া যেতে পারে এমন বৈশিষ্ট্যের সমতল সেটগুলিতে অবজেক্টটি পরিবর্তন করতে দেয়, আপনার বিদ্যমান ডিবি অবজেক্টের কোনও সম্পত্তি প্রয়োজন ছাড়াই মুছে ফেলা / ওভাররাইট করা হবে এমন উদ্বেগ ছাড়াই।

mongo-dot-notationডক্স থেকে নেওয়া :

var person = {
  firstName: 'John',
  lastName: 'Doe',
  address: {
    city: 'NY',
    street: 'Eighth Avenu',
    number: 123
  }
};



var instructions = dot.flatten(person)
console.log(instructions);
/* 
{
  $set: {
    'firstName': 'John',
    'lastName': 'Doe',
    'address.city': 'NY',
    'address.street': 'Eighth Avenu',
    'address.number': 123
  }
}
*/

এবং তারপরে এটি নিখুঁত নির্বাচনকারী রূপ দেয় - এটি কেবলমাত্র প্রদত্ত বৈশিষ্ট্যগুলি আপডেট করবে। সম্পাদনা: আমি কিছু সময় প্রত্নতত্ববিদ হতে পছন্দ করি;)


10

মঙ্গো আপনাকে একটি .সম্মেলন ব্যবহার করে নেস্টেড ডকুমেন্টগুলি আপডেট করতে দেয় । একবার দেখুন: মোংডব মধ্যে নেস্টেড ডকুমেন্ট আপডেট করা । একীভূত আপডেট সম্পর্কে অতীত থেকে এখানে আরও একটি প্রশ্ন রয়েছে, যেমনটি আপনি খুঁজছেন আমি বিশ্বাস করি: 'মার্জ' ডকুমেন্টের মাধ্যমে মঙ্গোডিবি পরমাণু আপডেট


6

এইভাবে এটি করার ক্ষেত্রে আমার সাফল্য ছিল:

db.collection.update(  { _id:...} , { $set: { 'key.another_key' : new_info  } } );

আমার একটি ফাংশন রয়েছে যা আমার প্রোফাইল আপডেটগুলি ডায়নামিকভাবে পরিচালনা করে

function update(prop, newVal) {
  const str = `profile.${prop}`;
  db.collection.update( { _id:...}, { $set: { [str]: newVal } } );
}

দ্রষ্টব্য: 'প্রোফাইল' আমার বাস্তবায়নের জন্য সুনির্দিষ্ট, এটি কেবলমাত্র কীটির স্ট্রিং যা আপনি সংশোধন করতে চান।


1

দেখে মনে হচ্ছে আপনি পার্স্টিয়াল অবজেক্ট সেট করতে পারবেন যা আপনার যা ইচ্ছা তা পূরণ করতে পারে।


এটা চেষ্টা করেছি. যদি আমার ভুল না হয় তবে আপনাকে আংশিক জিনিসগুলি সংরক্ষণ করতে দেয় না ... তবে ধন্যবাদ
ইরান মেডান

1
    // where clause DBObject
    DBObject query = new BasicDBObject("_id", new ObjectId(id));

    // modifications to be applied
    DBObject update = new BasicDBObject();

    // set new values
    update.put("$set", new BasicDBObject("param2","value2"));

   // update the document
    collection.update(query, update, true, false); //3rd param->upsertFlag, 4th param->updateMultiFlag

আপনার যদি একাধিক ক্ষেত্র আপডেট করতে হয়

        Document doc = new Document();
        doc.put("param2","value2");
        doc.put("param3","value3");
        update.put("$set", doc);

1

শুরু করা Mongo 4.2, db.collection.update()একত্রিতকরণ পাইপলাইন গ্রহণ করতে পারে, যা সমষ্টি অপারেটরগুলি ব্যবহারের অনুমতি দেয় যেমন $addFieldsইনপুট নথি এবং সদ্য যুক্ত হওয়া ক্ষেত্রগুলি থেকে সমস্ত বিদ্যমান ক্ষেত্রকে আউটপুট করে:

var new_info = { param2: "val2_new", param3: "val3_new" }

// { some_key: { param1: "val1", param2: "val2", param3: "val3" } }
// { some_key: { param1: "val1", param2: "val2"                 } }
db.collection.update({}, [{ $addFields: { some_key: new_info } }], { multi: true })
// { some_key: { param1: "val1", param2: "val2_new", param3: "val3_new" } }
// { some_key: { param1: "val1", param2: "val2_new", param3: "val3_new" } }
  • প্রথম অংশটি {}ম্যাচ ক্যোয়ারী, কোন নথিগুলি আপডেট করতে হবে তা ফিল্টার করে (এই ক্ষেত্রে সমস্ত নথি)।

  • দ্বিতীয় অংশটি [{ $addFields: { some_key: new_info } }]আপডেট সমষ্টি পাইপলাইন:

    • সমষ্টি পাইপলাইন ব্যবহারের ইঙ্গিতকারী স্কোয়ার বন্ধনীগুলি নোট করুন।
    • যেহেতু এটি একটি সমষ্টি পাইপলাইন, তাই আমরা ব্যবহার করতে পারি $addFields
    • $addFields আপনার যা প্রয়োজন ঠিক তা সম্পাদন করে: অবজেক্টটি আপডেট করা যাতে নতুন অবজেক্টটি বিদ্যমানটির সাথে ওভারলে / মিশে যায়:
    • এই ক্ষেত্রে, { param2: "val2_new", param3: "val3_new" }বিদ্যমান মধ্যে মিশে গিয়ে তৈরি করা হবে some_keyরেখে param1অস্পৃষ্ট এবং হয় যোগ অথবা উভয় প্রতিস্থাপন param2এবং param3
  • ভুলে যাবেন না { multi: true }, অন্যথায় কেবল প্রথম মিলের নথিটি আপডেট করা হবে।


1
db.collection.update(  { _id:...} , { $set: { some_key : new_info  } } 

প্রতি

db.collection.update( { _id: ..} , { $set: { some_key: { param1: newValue} } } ); 

এই সাহায্য আশা করি!


1

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

নীচের মত কিছু

db.employees.update(
    {type:"FT"},
    {$set:{salary:200000}},
    {upsert : true}
 )

0

ব্যবহার this সেট এই প্রক্রিয়া করতে

.update({"_id": args.dashboardId, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}})
.exec()
.then(dashboardDoc => {
    return {
        result: dashboardDoc
    };
}); 

0

প্রয়োজনীয় ডট পাথ সহ সম্পত্তি নামের সাথে আপডেট অবজেক্ট করুন। ("কোনওরকম।" + ওপির উদাহরণ থেকে) এবং তারপরে আপডেটটি ব্যবহার করুন।

//the modification that's requested
updateReq = { 
   param2 : "val2_new",
   param3 : "val3_new"   
}

//build a renamed version of the update request
var update = {};
for(var field in updateReq){
    update["somekey."+field] = updateReq[field];
}

//apply the update without modifying fields not originally in the update
db.collection.update({._id:...},{$set:update},{upsert:true},function(err,result){...});

0

হ্যাঁ, সর্বোত্তম উপায় হ'ল এই মন্তব্যে উল্লিখিত হিসাবে অবজেক্ট নোটেশনটিকে ফ্ল্যাট কী-মান স্ট্রিং উপস্থাপনায় রূপান্তর করা: https://stackoverflow.com/a/39357531/2529199

আমি এই এনপিএম লাইব্রেরিটি ব্যবহার করে একটি বিকল্প পদ্ধতি হাইলাইট করতে চেয়েছিলাম: https://www.npmjs.com/package/dot-object যা আপনাকে ডট নোটেশন ব্যবহার করে বিভিন্ন বস্তুতে ম্যানিপুলেট করতে দেয়।

ফাংশন ভেরিয়েবল হিসাবে কী-মানটি গ্রহণ করার সময় আমি এই প্যাটার্নটি প্রগ্রেটিকভাবে একটি নেস্টেড অবজেক্ট সম্পত্তি তৈরি করতে ব্যবহার করেছি:

const dot = require('dot-object');

function(docid, varname, varvalue){
  let doc = dot.dot({
      [varname]: varvalue 
  });

  Mongo.update({_id:docid},{$set:doc});
}

এই প্যাটার্নটি আমাকে নেস্টেড পাশাপাশি একক স্তরের বৈশিষ্ট্যগুলি বিনিময়যোগ্য হিসাবে ব্যবহার করতে এবং সেগুলিকে মঙ্গোতে পরিষ্কারভাবে sertোকাতে দেয়।

আপনার যদি জেএস অবজেক্টের সাথে কেবল মঙ্গোর বাইরে খেলা প্রয়োজন, বিশেষত ক্লায়েন্ট-সাইডে তবে মংগোর সাথে কাজ করার সময় ধারাবাহিকতা থাকলে, এই লাইব্রেরিটি আপনাকে উল্লিখিত mongo-dot-notationএনপিএম মডিউলের চেয়ে আরও বেশি বিকল্প দেয় ।

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



0

আপনার বিনিময়ে অবজেক্টটি আপডেট করার বিষয়ে চিন্তা করা উচিত এবং তারপরে অবজেক্টটি আপডেট করা ক্ষেত্রগুলি দিয়ে কেবল সঞ্চয় করা উচিত। নীচে কিছু মত

function update(_id) {
    return new Promise((resolve, reject) => {

        ObjModel.findOne({_id}).exec((err, obj) => {

            if(err) return reject(err)

            obj = updateObject(obj, { 
                some_key: {
                    param2 : "val2_new",
                    param3 : "val3_new"
                }
            })

            obj.save((err, obj) => {
                if(err) return reject(err)
                resolve(obj)
            })
        })
    })
}


function updateObject(obj, data) {

    let keys = Object.keys(data)

    keys.forEach(key => {

        if(!obj[key]) obj[key] = data[key]

        if(typeof data[key] == 'object') 
            obj[key] = updateObject(obj[key], data[key])
        else
            obj[key] = data[key]
    })

    return obj
}

0

আপনাকে এমবেডড ডকুমেন্টস ব্যবহার করতে হবে (পাথ অবজেক্টটি স্ট্রাইফাই)

let update = {}
Object.getOwnPropertyNames(new_info).forEach(param => {
   update['some_key.' + param] = new_info[param]
})

এবং তাই, জাভাস্ক্রিপ্টে আপনি আপডেট করতে স্প্রেড অপারেটর (...) ব্যবহার করতে পারেন

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