মঙ্গোডিবি - একটি নথির অ্যারেতে অবজেক্টগুলি আপডেট করুন (নেস্টেড আপডেট করা)


204

ধরে নিন আমাদের নীচের সংগ্রহ রয়েছে, যা সম্পর্কে আমার কয়েকটি প্রশ্ন রয়েছে:

{
    "_id" : ObjectId("4faaba123412d654fe83hg876"),
    "user_id" : 123456,
    "total" : 100,
    "items" : [
            {
                    "item_name" : "my_item_one",
                    "price" : 20
            },
            {
                    "item_name" : "my_item_two",
                    "price" : 50
            },
            {
                    "item_name" : "my_item_three",
                    "price" : 30
            }
    ]
}

1 - আমি "আইটেম_নাম": "মাই_াইটেম_টিউ" এর দাম বাড়িয়ে দিতে চাই এবং যদি এটি বিদ্যমান না থাকে তবে এটি "আইটেম" অ্যারেতে যুক্ত করা উচিত।

2 - আমি একই সাথে দুটি ক্ষেত্র আপডেট করতে পারি। উদাহরণস্বরূপ, "my_item_three" এর দাম বাড়ান এবং একই সাথে "মোট" (একই মান সহ) বৃদ্ধি করুন।

আমি মঙ্গোডিবি সাইডে এটি করতে পছন্দ করি, অন্যথায় আমাকে ক্লায়েন্ট-সাইড (পাইথন) এ নথিটি লোড করতে হবে এবং আপডেট নথিটি তৈরি করতে হবে এবং এটি মঙ্গোডিবিতে বিদ্যমান একটিতে প্রতিস্থাপন করতে হবে।

হালনাগাদ করুন আমি যা চেষ্টা করেছি এবং যদি কাজটি অবজায় থাকে তবে তা কাজ করে :

db.test_invoice.update({user_id : 123456 , "items.item_name":"my_item_one"} , {$inc: {"items.$.price": 10}})

তবে কীটি উপস্থিত না থাকলে এটি কিছুই করে না। এছাড়াও এটি কেবল নেস্টেড অবজেক্টটিকে আপডেট করে। এই আদেশটি দিয়ে "মোট" ক্ষেত্রটিও আপডেট করার উপায় নেই।


1
আমি মনে করি আপনি মঙ্গোতে এটি করতে পারবেন না, সম্ভবত এভাল ব্যবহার করে খুব ব্যথা করা ছাড়া। মঙ্গো ডেটা অপ্সে খুব সীমাবদ্ধ।
অ্যান্টি হাপালা

3
@Haapala: MongoDB $ Inc এবং upsert সঙ্গে আপডেট হয়েছে
jdi

1
@ জেডি হ্যাঁ হ্যাঁ, তবে এটি এখানে খুব বেশি সহায়তা করে না, তবে শর্তসাপেক্ষে তাঁর যা দরকার তা একাধিক ইনস, এবং যদি আইটেমটি উপস্থিত না থাকে তবে একটি $ পুশ দরকার।
অ্যান্টি হাপালা

উত্তর:


237

# 1 প্রশ্নের জন্য, আসুন এটি দুটি ভাগে বিভক্ত করুন। প্রথমে, "আইটেম.ইটিএম_নাম" "মাই_াইটেম_টওয়ো" সমান যে কোনও দস্তাবেজ বৃদ্ধি করুন। এর জন্য আপনাকে পজিশনাল "$" অপারেটরটি ব্যবহার করতে হবে। কিছুটা এইরকম:

 db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } , 
                {$inc : {"items.$.price" : 1} } , 
                false , 
                true);

নোট করুন যে এটি কেবল কোনও অ্যারেতে প্রথম মিলিত সাব-ডকুমেন্টকে বাড়িয়ে তুলবে (সুতরাং যদি আপনার কাছে অ্যারেতে "আইটেম_নাম" "আমার_সেট_টুই" সমান অন্য ডকুমেন্ট থাকে তবে এটি বাড়বে না)। তবে এটি আপনি যা চান তা হতে পারে।

দ্বিতীয় অংশটি কৌশলযুক্ত। আমরা "my_item_two" ছাড়াই একটি নতুন আইটেমিকে অ্যারেতে ঠেলাতে পারি:

 db.bar.update( {user_id : 123456, "items.item_name" : {$ne : "my_item_two" }} , 
                {$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
                false , 
                true);

আপনার প্রশ্ন # 2 এর জন্য উত্তরটি আরও সহজ। "My_item_three" থাকা যে কোনও নথিতে আইটেম_থ্রি এর মোট এবং দাম বাড়ানোর জন্য আপনি একই সময়ে একাধিক ক্ষেত্রে $ inc অপারেটরটি ব্যবহার করতে পারেন। কিছুটা এইরকম:

db.bar.update( {"items.item_name" : {$ne : "my_item_three" }} ,
               {$inc : {total : 1 , "items.$.price" : 1}} ,
               false ,
               true);

উত্তরের জন্য ধন্যবাদ. প্রশ্ন # 2 এর উত্তর নিখুঁত এবং কার্যকর কাজ করে :) তবে প্রশ্ন # 1 এর জন্য সমস্যাটি আপনার "ইউজার_আইডি" দ্বারা নথির সন্ধান করা উচিত, "আইটেম.আইটিএম_নেম" দ্বারা নয়। এই ক্ষেত্রে আমি পজিশনাল অপারেটরটি ব্যবহার করতে পারি না, কারণ আমি অনুসন্ধানের ক্যোয়ারিতে অ্যারে নির্দিষ্ট করে নেই। এছাড়াও আমি চাই দুটি অংশই একটি শটে করা হোক। (যদি সম্ভব হয়)
মজিদ

সুন্দর উদাহরণ। আমার মনে হয়েছিল যে আমি আমার উত্তরের লিঙ্কগুলি থেকে এই দিকটি স্পষ্ট করে দিচ্ছি, তবে তিনি যা খুঁজছিলেন তা না বলে আমি প্রতিরোধ পেতে থাকি। কীভাবে একাধিক ইনক করতে হবে তার উদাহরণগুলি দেখার জন্য ওপি-র প্রয়োজনের অনুমান করুন।
jdi

প্রশ্ন # 1 এর জন্য, আপনার আপডেটের প্রতিটি ক্যোয়ারী বিটটিতে ইউজার_আইড যুক্ত করে এটি দুটি অংশে করতে সক্ষম হওয়া উচিত (আমি সেই অনুসারে উত্তরটি সংশোধন করব)। একক শটে এটি করা সম্ভব কিনা তা নিয়ে আরও ভাবতে হবে।
matulef

6
আপডেট পদ্ধতিতে তৃতীয় এবং চতুর্থ পরামিতি কী কী? এবং কেন?
skmahawar

5
@skmahawar তৃতীয় এবং চতুর্থ প্যারাম সম্পর্কিত, ডকস.মোংডব.কম / ম্যানুয়াল / রেফারেন্স / মেমোথ / ডিবি.কোলেশন.আপডেট নির্দেশ করে যে এই বিকল্পগুলি যথাক্রমে "উপস্থাপক" এবং "বহু" এর জন্য for উপস্থাপনের জন্য, সত্য হিসাবে সেট করা থাকলে, কোনও দস্তাবেজ কোয়েরির মানদণ্ডের সাথে মেলে না এমন একটি নতুন দস্তাবেজ তৈরি করে। ডিফল্ট মানটি মিথ্যা, যা কোনও মিল পাওয়া না গেলে একটি নতুন দস্তাবেজ সন্নিবেশ করে না multi "একাধিকের জন্য, সত্য হিসাবে সেট করা থাকলে কোয়েরির মানদণ্ড পূরণ করে এমন একাধিক নথি আপডেট করে false যদি মিথ্যাতে সেট করা থাকে তবে একটি নথি আপডেট করে The ডিফল্ট মানটি হয় ভুয়া।
মাইক স্ট্র্যান্ড

24

একক ক্যোয়ারিতে এটি করার কোনও উপায় নেই। আপনাকে প্রথম ক্যোয়ারিতে নথিটি সন্ধান করতে হবে:

যদি দস্তাবেজ উপস্থিত থাকে:

db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } , 
                {$inc : {"items.$.price" : 1} } , 
                false , 
                true);

আর

db.bar.update( {user_id : 123456 } , 
                {$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
                false , 
                true);

শর্ত যুক্ত করার দরকার নেই {$ne : "my_item_two" }

মাল্টিথ্রেডেড এনভায়ুরমেন্টেও আপনাকে সতর্ক থাকতে হবে যে কেবল একটি থ্রেড একই সাথে দ্বিতীয়টি কার্যকর করতে পারে (সন্নিবেশের ক্ষেত্রে, যদি নথিটি পাওয়া যায় নি) অন্যথায় নকল এম্বেড নথি সন্নিবেশ করা হবে।


1
না, একটি একক ক্যোয়ারিতে এটি করার একটি উপায় রয়েছে, উপরে দেখুন
মার্টিজন শেফার

1
@ মার্তিজজনশেফার, আমি এই থ্রেডের কোথাও একক কোয়েরি হিসাবে এটি করার উপায় দেখছি না। এমনকি "উত্তর" 2 টি প্রশ্নের উত্তর ব্যবহার করে একই ব্যবহার করছে। আমি কিছু অনুপস্থিত করছি? আমি আরও আশা করছি যে কোনও মাল্টি থ্রেডিংয়ের সমস্যা রোধ করার জন্য একটি ক্যোয়ারিতে এটি করার একটি উপায় রয়েছে
ডিফেরারো

@ উডিট, আমি কীভাবে আইটেমগুলি ব্যবহার করতে পারি? যখন আমি একটি শর্ত যুক্ত করার চেষ্টা করি যেমন "কেবলমাত্র দাম 0 এর চেয়ে বেশি হলে" বৃদ্ধি করে, এটি কার্যকর হয় না - মূলত কিছুই আপডেট হয় না। আমি এটি যেখানে অবস্থাতে ব্যবহার করতে পারি, বা আমি কিছু মিস করছি? আইটেম। মূল্য: {{gt: 0}
ডিফেরারো

কিছু গায়েবি থাকতে হবে :)
মার্টিজন শেফার

3

আমরা $setআবেদিত ফাইলের অভ্যন্তরের নেস্টেড অ্যারে আপডেট করতে অপারেটরটি ব্যবহার করতে পারি update

db.getCollection('geolocations').update( 
   {
       "_id" : ObjectId("5bd3013ac714ea4959f80115"), 
       "geolocation.country" : "United States of America"
   }, 
   { $set: 
       {
           "geolocation.$.country" : "USA"
       } 
    }, 
   false,
   true
);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.