মঙ্গোডিবি সংগ্রহের কোনও অবজেক্ট অ্যারেতে কেবল অনুসন্ধানকারী উপাদানগুলি পুনরুদ্ধার করুন


377

ধরুন আমার সংগ্রহে আপনার কাছে নিম্নলিখিত নথি রয়েছে:

{  
   "_id":ObjectId("562e7c594c12942f08fe4192"),
   "shapes":[  
      {  
         "shape":"square",
         "color":"blue"
      },
      {  
         "shape":"circle",
         "color":"red"
      }
   ]
},
{  
   "_id":ObjectId("562e7c594c12942f08fe4193"),
   "shapes":[  
      {  
         "shape":"square",
         "color":"black"
      },
      {  
         "shape":"circle",
         "color":"green"
      }
   ]
}

জিজ্ঞাসা করুন:

db.test.find({"shapes.color": "red"}, {"shapes.color": 1})

অথবা

db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})

মেলে নথিটি (নথি 1) , কিন্তু সর্বদা এখানে অ্যারে আইটেমগুলির সাথে ফিরে আসে shapes:

{ "shapes": 
  [
    {"shape": "square", "color": "blue"},
    {"shape": "circle", "color": "red"}
  ] 
}

তবে, আমি কেবলমাত্র অ্যারেতে ডকুমেন্টটি (ডকুমেন্ট 1) পেতে চাই color=red:

{ "shapes": 
  [
    {"shape": "circle", "color": "red"}
  ] 
}

কিভাবে আমি এটি করতে পারব?

উত্তর:


416

মঙ্গোডিবি ২.২-এর নতুন $elemMatchপ্রক্ষেপণ অপারেটর কেবলমাত্র প্রথম ম্যাচের shapesউপাদানটি ধারণ করে ফেরত দস্তাবেজ পরিবর্তন করার জন্য অন্য উপায় সরবরাহ করে :

db.test.find(
    {"shapes.color": "red"}, 
    {_id: 0, shapes: {$elemMatch: {color: "red"}}});

রিটার্নস:

{"shapes" : [{"shape": "circle", "color": "red"}]}

২.২-এ আপনি এটি ব্যবহার করেও করতে পারেন $ projection operator, যেখানে $একটি প্রজেকশন অবজেক্ট ফিল্ডের নামটি কোয়েরি থেকে ক্ষেত্রের প্রথম মিলের অ্যারে উপাদানটির সূচক উপস্থাপন করে। নিম্নলিখিত হিসাবে উপরের মত একই ফলাফল প্রদান:

db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});

মঙ্গোডিবি 3.2 আপডেট

৩.২ রিলিজ দিয়ে শুরু করে, আপনি নতুন $filterএকাগ্রেশন অপারেটরটি প্রক্ষেপণের সময় একটি অ্যারে ফিল্টার করতে পারেন , এতে কেবল প্রথমটির পরিবর্তে সমস্ত ম্যাচ অন্তর্ভুক্ত করার সুবিধা রয়েছে ।

db.test.aggregate([
    // Get just the docs that contain a shapes element where color is 'red'
    {$match: {'shapes.color': 'red'}},
    {$project: {
        shapes: {$filter: {
            input: '$shapes',
            as: 'shape',
            cond: {$eq: ['$$shape.color', 'red']}
        }},
        _id: 0
    }}
])

ফলাফল:

[ 
    {
        "shapes" : [ 
            {
                "shape" : "circle",
                "color" : "red"
            }
        ]
    }
]

15
কোনও সমাধান যদি আমি এটির পরিবর্তে প্রথম উপাদানগুলির পরিবর্তে এটি মেলে এমন প্রতিটি উপাদানকে ফিরিয়ে দিতে চাই?
স্টিভ এনজি

আমি আশঙ্কা করছি আমি মঙ্গো 3.0.X :-(
চার্লিবার্বোনি

@ চর্লিবারব্রোনি তারপরে ব্যবহার করা অন্য উত্তরগুলির মধ্যে একটি ব্যবহার করুন aggregate
জনিএইচকে

এই ক্যোয়ারীটি কেবল অ্যারে "আকারগুলি" দেয় এবং এটি অন্যান্য ক্ষেত্রগুলিতে ফিরে আসবে না। অন্য ক্ষেত্রগুলিও কীভাবে ফেরাতে হবে কেউ জানেন?
মার্ক থিয়েন

1
এটিও কাজ করে:db.test.find({}, {shapes: {$elemMatch: {color: "red"}}});
পল

97

মঙ্গোডিবি ২.২++ এ নতুন একীকরণ ফ্রেমওয়ার্ক মানচিত্র / হ্রাস করার বিকল্প সরবরাহ করে। $unwindঅপারেটরকে আপনার আলাদা করতে ব্যবহার করা যেতে পারে shapesনথি একটি স্ট্রিম সঙ্গে মেলা করা যেতে পারে বা অ্যারে:

db.test.aggregate(
  // Start with a $match pipeline which can take advantage of an index and limit documents processed
  { $match : {
     "shapes.color": "red"
  }},
  { $unwind : "$shapes" },
  { $match : {
     "shapes.color": "red"
  }}
)

ফলাফল স্বরূপ:

{
    "result" : [
        {
            "_id" : ObjectId("504425059b7c9fa7ec92beec"),
            "shapes" : {
                "shape" : "circle",
                "color" : "red"
            }
        }
    ],
    "ok" : 1
}

6
@ জননিএইচকে: এই ক্ষেত্রে, $elemMatchঅন্য একটি বিকল্প। আমি আসলে একটি গুগল গ্রুপের প্রশ্নের মাধ্যমে এখানে পৌঁছেছি যেখানে m ইলেম ম্যাচটি কাজ করবে না কারণ এটি ডকুমেন্ট অনুসারে কেবল প্রথম ম্যাচটি দেয়।
স্টেনি

1
ধন্যবাদ, আমি এই সীমাবদ্ধতা সম্পর্কে অবগত ছিলাম না তাই এটি জেনে রাখা ভাল। আপনি যে মন্তব্যটি দিয়েছিলেন সেগুলি মুছে দেওয়ার জন্য দুঃখিত, আমি পরিবর্তে অন্য একটি উত্তর পোস্ট করার সিদ্ধান্ত নিয়েছি এবং মানুষকে বিভ্রান্ত করতে চাই না।
জনিএইচকে

3
@ জোহনিএইচকে: কোনও উদ্বেগ নেই, প্রশ্নের উত্তর এখন তিনটি কার্যকর রয়েছে ;-)
স্টেনি

অন্যান্য অনুসন্ধানকারীদের জন্য, আমি এটির পাশাপাশি যুক্ত করার চেষ্টাও করলাম { $project : { shapes : 1 } }- যা কাজ করে বলে মনে হচ্ছে এবং বদ্ধ দস্তাবেজগুলি বড় হলে আপনি সহায়ক হবেন এবং আপনি কেবল shapesমূল মানগুলি দেখতে চেয়েছিলেন ।
ব্যবহারকারী 1063287

2
@ ক্যালম্বার্ড আমি প্রাথমিক $ ম্যাচের মঞ্চটি অন্তর্ভুক্ত করার জন্য উদাহরণটি আপডেট করেছি। আপনি যদি আরও দক্ষ বৈশিষ্ট্যের পরামর্শে আগ্রহী হন তবে আমি সার্ভার -6612 দেখতে / উপস্থাপন করবো : মঙ্গোডিবি ইস্যু ট্র্যাকারটিতে $ এলেমম্যাচ প্রজেকশন স্পেসিফায়ারের মতো প্রক্ষেপণে একাধিক অ্যারে মান প্রজেক্ট করা সমর্থন করুন
স্টেনি

30

আরেকটি interesing উপায় ব্যবহার করা $ সম্পাদনা , যার মধ্যে নতুন অ্যাগ্রিগেশন বৈশিষ্ট্য MongoDB 2.6 । আপনি যদি ২.6 ব্যবহার করে থাকেন তবে আপনার এমন $ আনইন্ডিং লাগবে না যা আপনার বড় অ্যারেগুলি দেখাতে পারফরম্যান্সে সমস্যা তৈরি করতে পারে।

db.test.aggregate([
    { $match: { 
         shapes: { $elemMatch: {color: "red"} } 
    }},
    { $redact : {
         $cond: {
             if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
             then: "$$DESCEND",
             else: "$$PRUNE"
         }
    }}]);

$redact "নথিতে নিজেরাই সঞ্চিত তথ্যের উপর ভিত্তি করে নথিগুলির বিষয়বস্তু সীমাবদ্ধ করে" । সুতরাং এটি কেবলমাত্র নথির ভিতরে চলবে । এটি মূলত আপনার নথিটি নীচে শীর্ষে স্ক্যান করে এবং এটি আপনার ifঅবস্থার সাথে মেলে কিনা তা যাচাই করে তা যদি মিল হয় তবে তা $condসামগ্রীটি ( $$DESCEND) রাখবে বা ( $$PRUNE) সরিয়ে ফেলবে ।

উপরের উদাহরণে, প্রথমে $matchপুরো shapesঅ্যারেটি ফেরত দেয় এবং act রেডাক্ট এটিকে প্রত্যাশিত ফলাফলের দিকে নামিয়ে দেয়।

নোটটি {$not:"$color"}প্রয়োজনীয়, কারণ এটি শীর্ষ নথিকেও স্ক্যান করবে এবং শীর্ষ স্তরের $redactকোনও colorক্ষেত্র না পেলে এটি ফিরে আসবে falseযা পুরো দস্তাবেজটি আমরা চাই না p


1
নিখুঁত উত্তর. যেমনটি আপনি উল্লেখ করেছেন $ আনওয়াইন্ড প্রচুর পরিমাণে র‍্যাম গ্রহণ করবে। সুতরাং এটি তুলনা করা ভাল হবে।
মনোজপ্ট

আমার সন্দেহ আছে. উদাহরণস্বরূপ, "আকার" একটি অ্যারে is "$ Redact" "আকার" অ্যারেতে সমস্ত বস্তু স্ক্যান করবে ?? পারফরম্যান্সের ক্ষেত্রে এটি কীভাবে ভাল হবে ??
মনোজ্ট

এটি সব কিছু নয়, তবে আপনার প্রথম ম্যাচের ফলাফল। এই কারণেই আপনি $matchআপনার প্রথম সামগ্রিক মঞ্চ হিসাবে
রেখেছেন

Okkk .. যদি "রঙ" ফিল্ডে কোনও সূচক তৈরি হয়, তবুও এটি "আকার" অ্যারেতে সমস্ত বস্তু স্ক্যান করবে ??? কোন অ্যারে একাধিক অবজেক্টের মিলের দক্ষ উপায় হতে পারে ???
manojpt

2
উজ্জ্বল! আমি এখানে বুঝতে পারি না যে এখানে কীভাবে কাজ করা হয়। আমি এটিকে মূলত ছেড়ে দিয়েছি এবং এটি আমার পক্ষে কার্যকর হয়নি। একরকম, এটি মিল খুঁজে পেতে আকারগুলির অ্যারেতে দেখায়, তবে কোয়েরিটি কখন অ্যারেটি সন্ধান করবে তা নির্দিষ্ট করে না Like যেমন, যদি নথির আকার থাকে এবং উদাহরণস্বরূপ, আকারগুলি; q eq উভয় ম্যাচ জন্য অ্যারে চেহারা হবে? $ Redact কেবল ডকুমেন্টের মধ্যে এমন কিছু সন্ধান করছে যা 'যদি' শর্তের সাথে মেলে?
ওনোসা

30

সতর্কতা: এই উত্তরটি এমন একটি সমাধান সরবরাহ করে যা সেই সময়ে প্রাসঙ্গিক ছিল মঙ্গোডিবি ২.২ এবং তার নতুন বৈশিষ্ট্য প্রবর্তনের আগে। আপনি যদি মঙ্গোডিবি-র একটি সাম্প্রতিকতম সংস্করণ ব্যবহার করছেন তবে অন্যান্য উত্তরগুলি দেখুন।

ক্ষেত্র নির্বাচনকারী পরামিতি সম্পূর্ণ বৈশিষ্ট্যের মধ্যে সীমাবদ্ধ। এটি কোনও অ্যারের অংশ নির্বাচন করতে ব্যবহার করা যাবে না, কেবলমাত্র পুরো অ্যারে। আমি $ পজিশনাল অপারেটরটি ব্যবহার করার চেষ্টা করেছি , তবে এটি কার্যকর হয়নি।

সবচেয়ে সহজ উপায় হ'ল ক্লায়েন্টের মধ্যে কেবল আকারগুলি ফিল্টার করা ।

আপনার যদি সত্যিই মঙ্গোডিবি থেকে সঠিক আউটপুট প্রয়োজন হয় তবে আপনি আকারগুলি ফিল্টার করতে মানচিত্র-হ্রাস ব্যবহার করতে পারেন

function map() {
  filteredShapes = [];

  this.shapes.forEach(function (s) {
    if (s.color === "red") {
      filteredShapes.push(s);
    }
  });

  emit(this._id, { shapes: filteredShapes });
}

function reduce(key, values) {
  return values[0];
}

res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

db[res.result].find()

24

অ্যারে উপাদানের সাথে মিল রেখে আপনি কোয়েরি করতে আরও ভাল $sliceহ'ল অ্যারেতে থাকা উল্লেখযোগ্য অবজেক্টটি ফিরিয়ে আনতে সহায়ক।

db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})

$sliceআপনি যখন উপাদানটির সূচকটি জানেন তখন সহায়ক হয় তবে কখনও কখনও আপনি যে কোনও অ্যারে উপাদানটি আপনার মানদণ্ডের সাথে মেলে তা চান। আপনি $অপারেটরের সাথে মিলে যাওয়া উপাদানটি ফিরে আসতে পারেন ।



12

মঙ্গোদব সন্ধানের বাক্য গঠনটি হ'ল

    db.<collection name>.find(query, projection);

এবং দ্বিতীয় ক্যোয়ারী যা আপনি লিখেছেন তা হ'ল

    db.test.find(
    {shapes: {"$elemMatch": {color: "red"}}}, 
    {"shapes.color":1})

এতে আপনি $elemMatchক্যোয়ারী অংশে অপারেটরটি ব্যবহার করেছেন , আপনি যদি এই অপারেটরটিকে প্রজেকশন অংশে ব্যবহার করেন তবে আপনি পছন্দসই ফলাফল পাবেন। আপনি আপনার ক্যোয়ারী হিসাবে লিখতে পারেন

     db.users.find(
     {"shapes.color":"red"},
     {_id:0, shapes: {$elemMatch : {color: "red"}}})

এটি আপনাকে কাঙ্ক্ষিত ফলাফল দেবে।


1
এটি আমার পক্ষে কাজ করে। তবে এটি প্রদর্শিত হয় যে "shapes.color":"red"ক্যোয়ারী প্যারামিটারে (সন্ধান পদ্ধতির প্রথম প্যারামিটার) প্রয়োজনীয় নয় is আপনি এটির সাথে প্রতিস্থাপন করতে পারেন {}এবং একই ফলাফল পেতে পারেন।
এরিক ওলসন

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

এটি সবচেয়ে সহজ বলে মনে হচ্ছে, তবে আমি এটি কার্যকর করতে পারি না। এটি কেবল প্রথম ম্যাচের সাবডোকামেন্টটি প্রদান করে।
নিউম্যান

8

ধন্যবাদ JohnnyHK

এখানে আমি আরও কিছু জটিল ব্যবহার যুক্ত করতে চাই।

// Document 
{ 
"_id" : 1
"shapes" : [
  {"shape" : "square",  "color" : "red"},
  {"shape" : "circle",  "color" : "green"}
  ] 
} 

{ 
"_id" : 2
"shapes" : [
  {"shape" : "square",  "color" : "red"},
  {"shape" : "circle",  "color" : "green"}
  ] 
} 


// The Query   
db.contents.find({
    "_id" : ObjectId(1),
    "shapes.color":"red"
},{
    "_id": 0,
    "shapes" :{
       "$elemMatch":{
           "color" : "red"
       } 
    }
}) 


//And the Result

{"shapes":[
    {
       "shape" : "square",
       "color" : "red"
    }
]}

7

আপনার শুধু ক্যোয়ারি চালানো দরকার

db.test.find(
{"shapes.color": "red"}, 
{shapes: {$elemMatch: {color: "red"}}});

এই ক্যোয়ারির আউটপুট হয়

{
    "_id" : ObjectId("562e7c594c12942f08fe4192"),
    "shapes" : [ 
        {"shape" : "circle", "color" : "red"}
    ]
}

যেমনটি আপনি প্রত্যাশা করেছিলেন এটি অ্যারে থেকে সঠিক ক্ষেত্রটি দেবে যা রঙের সাথে মেলে: 'লাল'।


3

$ প্রকল্পের পাশাপাশি এটি আরও উপযুক্ত হবে যে অন্যান্য বুদ্ধিমান ম্যাচিং উপাদানগুলি নথিতে অন্যান্য উপাদানগুলির সাথে একত্রে ক্লাব করা হবে।

db.test.aggregate(
  { "$unwind" : "$shapes" },
  { "$match" : {
     "shapes.color": "red"
  }},
{"$project":{
"_id":1,
"item":1
}}
)

আপনি কি প্লিজ বর্ণনা করতে পারবেন যে এটি কোনও ইনপুট এবং আউটপুট সেট দিয়ে সাফল্য অর্জন করবে?
আলেকজান্ডার মিলস

2

একইভাবে আপনি একাধিক জন্য খুঁজে পেতে পারেন

db.getCollection('localData').aggregate([
    // Get just the docs that contain a shapes element where color is 'red'
  {$match: {'shapes.color': {$in : ['red','yellow'] } }},
  {$project: {
     shapes: {$filter: {
        input: '$shapes',
        as: 'shape',
        cond: {$in: ['$$shape.color', ['red', 'yellow']]}
     }}
  }}
])

এই উত্তরটি প্রকৃতপক্ষে prefered 4.x উপায় হল: $matchতারপর, স্থান কেটে ফেলতে $filterকি আপনি চান এর রাখা, ইনপুট ক্ষেত্র মুছে যাওয়ার (ব্যবহারের আউটপুট $filterক্ষেত্রের উপর shapesথেকে $projectথেকে ফিরে shapes। স্টাইল নোট: যেমন ক্ষেত্র নাম ব্যবহার করতে ভাল হয় না asযুক্তি কারণ যা পরে সঙ্গে গুলিয়ে হতে পারে $$shapeএবং $shapeআমি পছন্দ করি। zzযেমন asক্ষেত্র কারণ এটি ঠিক দাঁড়িয়েছে আউট।
Buzz- এ Moschetti

1
db.test.find( {"shapes.color": "red"}, {_id: 0})

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

1

সমষ্টি ফাংশন এবং $projectনথিতে নির্দিষ্ট অবজেক্ট ক্ষেত্রটি পেতে ব্যবহার করুন

db.getCollection('geolocations').aggregate([ { $project : { geolocation : 1} } ])

ফলাফল:

{
    "_id" : ObjectId("5e3ee15968879c0d5942464b"),
    "geolocation" : [ 
        {
            "_id" : ObjectId("5e3ee3ee68879c0d5942465e"),
            "latitude" : 12.9718313,
            "longitude" : 77.593551,
            "country" : "India",
            "city" : "Chennai",
            "zipcode" : "560001",
            "streetName" : "Sidney Road",
            "countryCode" : "in",
            "ip" : "116.75.115.248",
            "date" : ISODate("2020-02-08T16:38:06.584Z")
        }
    ]
}

0

যদিও 9,6 বছর আগে প্রশ্নটি জিজ্ঞাসা করা হয়েছিল, এটি অসংখ্য লোকের জন্য প্রচুর সহায়ক হয়েছে, আমি তাদের মধ্যে অন্যতম। আপনার সমস্ত প্রশ্ন, ইঙ্গিত এবং জবাবের জন্য সবাইকে ধন্যবাদ এখানে একটি উত্তর থেকে বাছাই করা .. আমি খুঁজে পেয়েছি যে নিম্নলিখিত পদ্ধতিটি পিতামাতার নথিতে অন্যান্য ক্ষেত্রগুলি প্রজেক্ট করতেও ব্যবহার করা যেতে পারে his এটি কারও পক্ষে সহায়ক হতে পারে।

নিম্নলিখিত নথির জন্য, প্রয়োজনীয় ছিল যে কোনও কর্মচারী (এমপি # 7839) এর 2020 সালের জন্য তার ছুটির ইতিহাস সেট আছে কিনা তা খুঁজে বের করা Leave পিতামাতার কর্মচারী নথির মধ্যে এমবেডড ডকুমেন্ট হিসাবে ছেড়ে যাওয়ার ইতিহাস প্রয়োগ করা হয়।

db.employees.find( {"leave_history.calendar_year": 2020}, 
    {leave_history: {$elemMatch: {calendar_year: 2020}},empno:true,ename:true}).pretty()


{
        "_id" : ObjectId("5e907ad23997181dde06e8fc"),
        "empno" : 7839,
        "ename" : "KING",
        "mgrno" : 0,
        "hiredate" : "1990-05-09",
        "sal" : 100000,
        "deptno" : {
                "_id" : ObjectId("5e9065f53997181dde06e8f8")
        },
        "username" : "none",
        "password" : "none",
        "is_admin" : "N",
        "is_approver" : "Y",
        "is_manager" : "Y",
        "user_role" : "AP",
        "admin_approval_received" : "Y",
        "active" : "Y",
        "created_date" : "2020-04-10",
        "updated_date" : "2020-04-10",
        "application_usage_log" : [
                {
                        "logged_in_as" : "AP",
                        "log_in_date" : "2020-04-10"
                },
                {
                        "logged_in_as" : "EM",
                        "log_in_date" : ISODate("2020-04-16T07:28:11.959Z")
                }
        ],
        "leave_history" : [
                {
                        "calendar_year" : 2020,
                        "pl_used" : 0,
                        "cl_used" : 0,
                        "sl_used" : 0
                },
                {
                        "calendar_year" : 2021,
                        "pl_used" : 0,
                        "cl_used" : 0,
                        "sl_used" : 0
                }
        ]
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.