দস্তাবেজগুলির জন্য ক্যোয়ারী যেখানে অ্যারের আকার 1 এর চেয়ে বেশি হয়


664

আমার নিম্নোক্ত বিন্যাসে নথি সহ একটি মঙ্গোডিবি সংগ্রহ রয়েছে:

{
  "_id" : ObjectId("4e8ae86d08101908e1000001"),
  "name" : ["Name"],
  "zipcode" : ["2223"]
}
{
  "_id" : ObjectId("4e8ae86d08101908e1000002"),
  "name" : ["Another ", "Name"],
  "zipcode" : ["2224"]
}

আমি বর্তমানে একটি নির্দিষ্ট অ্যারের আকারের সাথে মেলে এমন নথিগুলি পেতে পারি:

db.accommodations.find({ name : { $size : 2 }})

এটি nameঅ্যারেতে 2 টি উপাদান সহ ডকুমেন্টগুলি সঠিকভাবে প্রদান করে । তবে, ক্ষেত্রটিতে 2 টিরও বেশি অ্যারের আকার রয়েছে এমন $gtসমস্ত দস্তাবেজ ফিরিয়ে দেওয়ার জন্য আমি কোনও আদেশ করতে পারি না name:

db.accommodations.find({ name : { $size: { $gt : 1 } }})

আমি কীভাবে nameএকের চেয়ে বড় আকারের অ্যারে সহ সমস্ত দস্তাবেজগুলি নির্বাচন করতে পারি (পছন্দসইভাবে বর্তমান তথ্য কাঠামোটি পরিবর্তন না করে)?


3
মঙ্গোডিবির নতুন সংস্করণগুলিতে $ আকারের অপারেটর রয়েছে; আপনার @ টোবিয়ার উত্তরটি পরীক্ষা করা উচিত
AlbertEngelB ২

4
আসল সমাধান: FooArray: {$ gt: {$ আকার: 'দৈর্ঘ্য'}} -> দৈর্ঘ্য যে কোনও সংখ্যা হতে পারে
সের্গি নাদাল

উত্তর:


489

হালনাগাদ:

মোংডব ভার্সনের জন্য ২.২+ আরও কার্যকরী উপায় যা জহ্নিনিএইচকে অন্য উত্তরে বর্ণনা করেছেন ।


1. ব্যবহার $ যেখানে

db.accommodations.find( { $where: "this.name.length > 1" } );

কিন্তু ...

জাভাস্ক্রিপ্ট এই পৃষ্ঠায় তালিকাভুক্ত নেটিভ অপারেটরগুলির চেয়ে আরও ধীরে ধীরে কার্যকর করে তবে এটি খুব নমনীয়। আরও তথ্যের জন্য সার্ভার-সাইড প্রসেসিং পৃষ্ঠাটি দেখুন।

2. অতিরিক্ত ক্ষেত্র তৈরি করুন NamesArrayLength, এটি অ্যারে দৈর্ঘ্যের সাথে আপডেট করুন এবং তারপরে কোয়েরিতে ব্যবহার করুন:

db.accommodations.find({"NamesArrayLength": {$gt: 1} });

এটি আরও ভাল সমাধান হবে, এবং আরও দ্রুত কাজ করবে (আপনি এটিতে সূচক তৈরি করতে পারেন)।


4
দুর্দান্ত, আপনি নিখুঁত ছিল ধন্যবাদ। যদিও আমার কাছে আসলে কিছু ডকুমেন্ট রয়েছে যার নাম নেই তাই কোয়েরিটিটি সংশোধন করতে হবে: db.accommodations.find ($ $ যেখানে: "যদি (this.name && this.name.length> 1) this এটিকে ফেরত দিন ;; "});
এমসন

আপনাকে স্বাগতম, হ্যাঁ আপনি যে কোনও জাভাস্ক্রিপ্ট ব্যবহার করতে পারেন $whereএটি খুব নমনীয়।
অ্যান্ড্রু ওরিচ

8
@ দয়া করে আমি মনে করব যে {"নাম": {$ বিদ্যমান: 1}, $ যেখানে: "this.name.lenght> 1"} ... এর মতো কিছু করা দ্রুততর হবে} ... ধীর জাভাস্ক্রিপ্ট ক্যোয়ারিতে অংশটি হ্রাস করুন। আমি ধরে নিই যে এটি কাজ করে এবং $ এর উপস্থিতির উচ্চতর প্রাধান্য থাকবে।
nairbv

1
আপনি কোয়েরিতে জাভাস্ক্রিপ্ট এম্বেড করতে পারেন এমন আমার ধারণা ছিল না, জেসন জটিল হতে পারে। এর মধ্যে অনেকগুলি প্রশ্নের এক সময় কেবল হাতে প্রবেশ করা হয় তাই অপ্টিমাইজেশনের প্রয়োজন হয় না। আমি এই কৌশলটি প্রায়শই +1
-14

3
অ্যারে থেকে উপাদানগুলি যুক্ত / অপসারণের পরে, আমাদের "নামস আরেএলইংথ" এর গণনাটি আপডেট করতে হবে। এটি কি একক ক্যোয়ারিতে করা যায়? অথবা এর জন্য 2 টি ক্যোয়ারী দরকার, একটি অ্যারে আপডেট করার জন্য এবং অন্যটি গণনা আপডেট করার জন্য?
ওয়ার্লর্ড

1325

মঙ্গোডিবি ২.২+ তে এটি করার আরও একটি কার্যকর উপায় আছে যে আপনি ক্যোয়ারী অবজেক্ট কীগুলিতে সংখ্যাযুক্ত অ্যারে সূচকগুলি ব্যবহার করতে পারেন।

// Find all docs that have at least two name array elements.
db.accommodations.find({'name.1': {$exists: true}})

আপনি এই ক্যোয়ারীটিকে একটি সূচি দিয়ে সমর্থন করতে পারেন যা একটি আংশিক ফিল্টার এক্সপ্রেশন ব্যবহার করে (3.2+ প্রয়োজন):

// index for at least two name array elements
db.accommodations.createIndex(
    {'name.1': 1},
    {partialFilterExpression: {'name.1': {$exists: true}}}
);

16
কেউ দয়া করে ব্যাখ্যা করতে পারে কীভাবে এটি সূচী করা যায়।
বেন

26
এটি কতটা কার্যকর এবং আমি কীভাবে 'বাক্সের বাইরে' আপনি এই সমাধানটি খুঁজতে চেয়েছিলেন তা নিয়ে আমি সত্যিই মুগ্ধ হয়েছি। এটি 2.6-তেও কাজ করে।
আর্থলেলন

2
3.0 পাশাপাশি কাজ করে। এটি সন্ধানের জন্য আপনাকে অনেক ধন্যবাদ।
পিকনেজী

1
কোন পার্থক্য, সত্যিই @Dims: {'Name Field.1': {$exists: true}}
জনিএইচকে

9
@JoseRicardoBustosM। এটি সেই দস্তাবেজগুলিতে সন্ধান করবে যেখানে কমপক্ষে 1 টি উপাদান nameরয়েছে তবে ওপি 1 টিরও বেশি বড় সন্ধান করছে
জনি এইচকে

127

আমি বিশ্বাস করি এটি আপনার প্রশ্নের উত্তর দেয় এটি দ্রুততম ক্যোয়ারী, কারণ এটি কোনও ব্যাখ্যাযুক্ত $whereধারা ব্যবহার করে না :

{$nor: [
    {name: {$exists: false}},
    {name: {$size: 0}},
    {name: {$size: 1}}
]}

এর অর্থ "নামবিহীন সমস্ত কাগজপত্র (অস্তিত্বহীন বা খালি অ্যারে নয়) বা কেবল একটি নাম সহ"।

টেস্ট:

> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>

9
@ ভাইরেন আমি জানি না এটি অবশ্যই জাভাস্ক্রিপ্ট সমাধানগুলির চেয়ে ভাল ছিল তবে নতুন মঙ্গোডিবিয়ের জন্য আপনার সম্ভবত ব্যবহার করা উচিত{'name.1': {$exists: true}}
টোবিয়া

@ তোবিয়ার আমার প্রথম ব্যবহারটি ছিল $ কেবলমাত্র বিদ্যমান তবে এটি আসলে পুরো টেবিল স্ক্যানটি খুব ধীর করে দেয়। db.test.find ({"নাম": "abc", "d.5": {$ বিদ্যমান: সত্য}, "d.6": {$ বিদ্যমান: সত্য}}) "n পুনরায় তৈরি": 46525, "এক্সিকিউশনটাইমমিলিস ": 167289," টোটালকিজ এক্সামিনড ": 10990840," টোটাল ডকস পরীক্ষিত ": 10990840," ইনপুটসটেজ ": stage" পর্যায় ":" আইএক্সএসসিএন "," কীপ্যাটার্ন ": {" নাম ": 1," ডি ": 1}," সূচকনাম " : "নাম_1_d_1", "দিকনির্দেশ": "ফরোয়ার্ড", "ইনডেক্সবাউন্ডস": {"নাম": ["[\" এবিসি \ ", \" অ্যাবসি \ "]"], "ডি": ["মিনকে, ম্যাক্সে ] "]} You আপনি যদি দেখতে পান এটি পুরো টেবিলটি স্ক্যান করে।

অন্যান্য বিকল্পগুলির প্রস্তাব দেওয়ার জন্য উত্তরটি আপডেট করতে ভাল লাগবে (যেমন 'name.1': {$exists: true}}এবং এটিও কারণ এটি "1" এর জন্য হার্ডকোডযুক্ত এবং একটি স্বেচ্ছাসেবী বা প্যারামেট্রিক ন্যূনতম অ্যারে দৈর্ঘ্যের সাথে
মাপসই হয় না

1
এটি দ্রুত হতে পারে তবে আপনি তালিকা> এন, যেখানে এন ছোট নয় তা সন্ধান করলে আলাদা হয়ে যেতে পারে।
ব্র্যান্ডন হিল

62

আপনিও সামগ্রিক ব্যবহার করতে পারেন:

db.accommodations.aggregate(
[
     {$project: {_id:1, name:1, zipcode:1, 
                 size_of_name: {$size: "$name"}
                }
     },
     {$match: {"size_of_name": {$gt: 1}}}
])

// আপনি দস্তাবেজকে ট্রানজিট করতে "আকার_চ__নাম" যুক্ত করুন এবং এটি নামের আকারটি ফিল্টার করতে ব্যবহার করুন


@ জনিএইচকে এর সাথে এই সমাধানটি সর্বাধিক সাধারণ, যেহেতু এটি কোনও অ্যারের আকারের জন্য ব্যবহার করা যেতে পারে।
অরুন

যদি আমি প্রজেকশনের অভ্যন্তরে "সাইজ_অফ_নাম" ব্যবহার করতে চাই তবে আমি কীভাবে এটি করতে পারি ?? প্রকৃতপক্ষে আমি প্রজেকশনটির ভিতরে $ স্লাইসটি ব্যবহার করতে চাই যেখানে এর মান $ স্লাইসের সমান: [0, "আকার_মুখে_নাম" - এড়িয়ে যান] ??
সুধাংশু গৌড়

44

এরকম কিছু করার চেষ্টা করুন:

db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})

1 হ'ল সংখ্যা, আপনি যদি 50 টিরও বেশি রেকর্ড পেতে চান তবে অ্যারেনেম করুন 5050 ধন্যবাদ।



আমি ভবিষ্যত থেকে এসেছি এবং এটির প্রশংসা করতাম: এই সমাধানটি সেই অবস্থানের কোনও উপাদান উপস্থিত রয়েছে কিনা তা যাচাই করেই কাজ করে। সুতরাং, সংগ্রহ অবশ্যই বৃহত্তর | সেই সংখ্যার তুলনায় সমান।
MarAvFe

আমরা কি কোয়েরির ভিতরে "অ্যারেনেম। <সোম_নাম>" এর মতো কিছু গতিশীল নম্বর রাখতে পারি?
সাহিল মহাজন

হ্যাঁ আপনি যে কোনও নম্বর ব্যবহার করতে পারেন। আপনি যদি N এর চেয়ে বেশি রেকর্ড পেতে চান তবে এন পাস করুন।
আমান গোয়েল

36

উপরের কেউই আমার পক্ষে কাজ করেনি। একজন এটি করেছে তাই আমি এটি ভাগ করছি:

db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )

জাভাস্ক্রিপ্টটি মঙ্গডব দ্বারা সরবরাহিত নেটিভ অপারেটরগুলির চেয়ে আরও ধীরে ধীরে কার্যকর করে তবে এটি খুব নমনীয়। দেখুন: স্ট্যাকওভারফ্লো.com / a / 7811259 / 2893073 , সুতরাং চূড়ান্ত সমাধানটি হ'ল: stackoverflow.com/a/15224544/2893073
এডি

26

আপনি নিয়মিত ক্যোয়ারিতে একত্রিতকরণ ফাংশনগুলি ব্যবহার করতে $ এক্সপ্রেস (3.6 মঙ্গো সংস্করণ অপারেটর) ব্যবহার করতে পারেন।

তুলনা query operatorsবনাম aggregation comparison operators

db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})

আপনি কীভাবে এমন $nameএকটি অ্যারের পরিবর্তে পাস করবেন যা একটি সাব-ডকুমেন্ট, উদাহরণস্বরূপ "ব্যক্তি" রেকর্ডে passport.stamps? আমি বিভিন্ন উদ্ধৃতি সমন্বয় চেষ্টা করেছি কিন্তু আমি পেয়েছি "The argument to $size must be an array, but was of type: string/missing"
ড্যান ড্যাসকলেসকু

3
@ ড্যানডাসক্লেস্কু দেখে মনে হচ্ছে যে সমস্ত নথিগুলিতে স্ট্যাম্প উপস্থিত নেই। স্ট্যাম্প উপস্থিত না থাকলে আপনি খালি অ্যারে আউটপুট দিতে ifNull ব্যবহার করতে পারেন । এরকম কিছুdb.col.find({$expr:{$gt:[{$size:{$ifNull:["$passport.stamps", []]}}, 1]}})
সাগর বীরম


22

মঙ্গোডিবি ৩.6 এর মধ্যে $ এক্সপ্রেস https://docs.mongodb.com/manual/references/operator/query/expr/

আপনি $ ম্যাচের অভ্যন্তরে কোনও এক্সপ্রেশন মূল্যায়ন করতে $ এক্সপ্রেস ব্যবহার করতে পারেন, বা খুঁজে পেতে পারেন।

{ $match: {
           $expr: {$gt: [{$size: "$yourArrayField"}, 0]}
         }
}

বা সন্ধান করুন

collection.find({$expr: {$gte: [{$size: "$yourArrayField"}, 0]}});

1
সঠিক হওয়ার পরে, এটি একটি সদৃশ উত্তর। দেখুন stackoverflow.com/a/48410837/2424641 @ user2683814 দ্বারা
SteveB

13

নির্দিষ্ট দৈর্ঘ্যের চেয়ে বড় অ্যারের ক্ষেত্রের আইটেমগুলি খুঁজতে আমি এই সমাধানটি পেয়েছি

db.allusers.aggregate([
  {$match:{username:{$exists:true}}},
  {$project: { count: { $size:"$locations.lat" }}},
  {$match:{count:{$gt:20}}}
])

প্রথম ম্যাচের সমষ্টিটি একটি দলিল ব্যবহার করে যা সমস্ত দস্তাবেজের ক্ষেত্রে সত্য। যদি ফাঁকা হয়, আমি পেতাম

"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"

এই মূলত হিসাবে একই উত্তর এই এক , 2 বছর আগে প্রদান করা হয়েছে।
ড্যান ড্যাসকলেসকু

1

আমি এর পুরানো প্রশ্নটি জানি, তবে আমি এটি $ gte এবং $ আকারের সাথে সন্ধান করছি am আমি মনে করি () দ্রুত খুঁজে পেতে।

db.getCollection('collectionName').find({ name : { $gte : {  $size : 1 } }})

-5

যদিও উপরের সমস্তটি উত্তর দেয়, আপনি মূলত যা করার চেষ্টা করেছিলেন সেটি সঠিক পদ্ধতি ছিল, তবে আপনার কেবল বাক্যটি উল্টিয়ে দেওয়া হয়েছে ("$ আকার" এবং "$ জিটি") স্যুইচ করুন ..

সঠিক:

db.collection.find({items: {$gt: {$size: 1}}})

ত্রুটিপূর্ণ:

db.collection.find({items: {$size: {$gt: 1}}})

1
আমি এত এত জনসংখ্যা কেন দেখছি না - এটি আমার পক্ষে নিখুঁতভাবে কাজ করে!
জ্যাক স্টোকস

আমি ডাউনওয়েট করি নি, তবে এটি কার্যকর হয় না (v4.2)।
এভেজেনি নাবোকভ

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