दस्तावेज़ों के लिए क्वेरी जहाँ सरणी का आकार 1 से अधिक है


664

मेरे पास निम्नलिखित प्रारूप में दस्तावेजों के साथ एक MongoDB संग्रह है:

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

मुझे वर्तमान में दस्तावेज़ मिल सकते हैं जो एक विशिष्ट सरणी आकार से मेल खाते हैं:

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

यह nameसरणी में 2 तत्वों के साथ दस्तावेजों को सही ढंग से वापस करता है । हालाँकि, मैं उन $gtसभी दस्तावेज़ों को वापस करने के लिए कमांड नहीं कर सकता जहाँ nameफ़ील्ड का आकार 2 से अधिक है:

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

मैं nameएक से अधिक आकार के एक सरणी के साथ सभी दस्तावेजों का चयन कैसे कर सकता हूं (अधिमानतः वर्तमान डेटा संरचना को संशोधित किए बिना)?


3
MongoDB के नए संस्करणों में $ आकार ऑपरेटर है; आपको @ तोबिया के जवाब की जांच करनी चाहिए
अल्बर्टबेंगल बी

4
वास्तविक समाधान: FooArray: {$ gt: {$ size: 'length'}} -> लेन किसी भी संख्या में हो सकता है
Sergi Nadal

जवाबों:


489

अपडेट करें:

Mongodb संस्करणों के लिए 2.2+ अधिक कुशल तरीका यह है कि @JohnnyHK द्वारा एक अन्य उत्तर में वर्णित किया गया है ।


1. $ का उपयोग कर कहाँ

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

परंतु...

जावास्क्रिप्ट इस पृष्ठ पर सूचीबद्ध देशी ऑपरेटरों की तुलना में अधिक धीमी गति से निष्पादित करता है, लेकिन बहुत लचीला है। अधिक जानकारी के लिए सर्वर-साइड प्रोसेसिंग पेज देखें।

2. अतिरिक्त फ़ील्ड बनाएं NamesArrayLength, इसे नाम सरणी लंबाई के साथ अपडेट करें और फिर प्रश्नों में उपयोग करें:

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

यह बेहतर समाधान होगा, और बहुत तेज़ी से काम करेगा (आप इस पर सूचकांक बना सकते हैं)।


4
महान, यह सही था धन्यवाद। हालाँकि मेरे पास वास्तव में कुछ दस्तावेज हैं जिनका नाम ऐसा नहीं है ताकि क्वेरी को संशोधित किया जा सके: db.accommodations.find ({$ जहाँ: "अगर (यह .name && this.name.length> 1) {इसे वापस करें ;} "});
एम्सन

आपका स्वागत है, हाँ आप किसी भी जावास्क्रिप्ट का उपयोग कर सकते हैं $where, यह बहुत लचीला है।
एंड्रयू ऑरसिच

8
@ मुझे लगता है कि यह {"नाम": {$ मौजूद: 1}, $ जहाँ: "this.name.lenght> 1"} जैसे कुछ करने के लिए जल्दी होगा ... धीमी जावास्क्रिप्ट क्वेरी में भाग को कम करना। मुझे लगता है कि काम करता है और यह है कि $ मौजूद उच्च प्राथमिकता होगी।
nairbv

1
मुझे नहीं पता था कि आप क्वेरी में जावास्क्रिप्ट एम्बेड कर सकते हैं, json बोझिल हो सकता है। इनमें से कई प्रश्न केवल एक बार हाथ से दर्ज किए जाते हैं इसलिए अनुकूलन की आवश्यकता नहीं होती है। मैं इस ट्रिक का अक्सर इस्तेमाल करता हूँ +1
Pferrel

3
ऐरे से तत्वों को जोड़ने / हटाने के बाद, हमें "NamesArrayLength" की गिनती को अपडेट करने की आवश्यकता है। क्या यह एक ही प्रश्न में किया जा सकता है? या इसके लिए 2 प्रश्नों की आवश्यकता है, एक एरे को अपडेट करने के लिए और दूसरा काउंट को अपडेट करने के लिए?
वारलॉर्ड

1326

MongoDB 2.2+ में ऐसा करने के लिए एक अधिक कुशल तरीका है कि अब आप क्वेरी ऑब्जेक्ट कुंजियों में संख्यात्मक सरणी इंडेक्स का उपयोग कर सकते हैं।

// 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 aswell पर काम करता है। इसे पाने के लिए बहुत-बहुत धन्यवाद।
pikanezi

1
@ कोई अंतर नहीं, वास्तव में {'Name Field.1': {$exists: true}}:।
जॉनीएचके

9
@JoseRicardoBustosM। यही कारण है कि डॉक्स जहां मिलेगा nameशामिल कम से कम 1 तत्व है, लेकिन ओपी लिए देख रहा था अधिक से अधिक की तुलना में 1.
JohnnyHK

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
@ वीरेन मुझे नहीं पता। यह निश्चित रूप से जावास्क्रिप्ट समाधानों से बेहतर था, लेकिन नए MongoDB के लिए आपको संभवतः उपयोग करना चाहिए{'name.1': {$exists: true}}
टोबिया

@ टोबिया मेरा पहला उपयोग केवल $ मौजूद था, लेकिन यह वास्तव में बहुत धीमी गति से पूरे टेबल स्कैन का उपयोग करता है। db.test.find ({"name": "abc", "d.5": {$ मौजूद: true}, "d.6": {$ मौजूद: true}}) "nReturned": 46525, "निष्पादन टाइमलाइन" "", 167289, "TotalKeysExamined": 10990840, "TotalDocsExamined": 10990840, "inputStage": {"stage": "IXSCAN", "keytattern": {"name": 1, "d": 1}, "indexName" : "name_1_d_1", "दिशा": "फ़ॉरवर्ड", "इंडेक्सबाउंड्स": {"नाम": ["[\" abc \ ", \" abc \ "]"], "d": ["[Mineyey, MaxKey] ] "]}} यदि आप इसे पूरी तालिका स्कैन करते हुए देखते हैं।

अन्य विकल्पों की सिफारिश करने के लिए उत्तर को अपडेट करना अच्छा होगा (जैसे '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}}}
])

// आप दस्तावेज़ को स्थानांतरित करने के लिए "size_of_name" जोड़ते हैं और इसका उपयोग नाम के आकार को फ़िल्टर करने के लिए करते हैं


यह समाधान सबसे सामान्य है, साथ ही @ जॉनीएचके भी क्योंकि इसका उपयोग किसी भी सरणी आकार के लिए किया जा सकता है।
अरुण

अगर मैं प्रक्षेपण के अंदर "size_of_name" का उपयोग करना चाहता हूं तो मैं कैसे कर सकता हूं ?? वास्तव में मैं प्रक्षेपण के अंदर $ स्लाइस का उपयोग करना चाहता हूं जहां इसका मूल्य $ स्लाइस के बराबर है: [0, "size_of_name" - छोड़ें] ??
सुधांशु गौड़

44

कुछ इस तरह से करने की कोशिश करें:

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

1 नंबर है, यदि आप 50 से अधिक रिकॉर्ड प्राप्त करना चाहते हैं तो ArrayName.50 धन्यवाद करें।


2
तीन साल पहले भी यही जवाब दिया गया था
दान डैस्कलेस्कु

मैं भविष्य से हूँ और इसकी सराहना की होगी: यदि कोई तत्व उक्त स्थान पर मौजूद है, तो यह जाँच कर काम करता है। इसलिए, संग्रह उस संख्या से अधिक होना चाहिए।
MarAvFe

क्या हम क्वेरी के अंदर "ArrayName। <some_num>" जैसे कुछ डायनामिक नंबर डाल सकते हैं?
साहिल महाजन

हां आप किसी भी नंबर का उपयोग कर सकते हैं। यदि आप N से अधिक रिकॉर्ड प्राप्त करना चाहते हैं तो n पास करें।
अमन गोयल

36

उपरोक्त में से किसी ने भी मेरे लिए काम नहीं किया। इसने ऐसा किया इसलिए मैं इसे साझा कर रहा हूं:

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

जावास्क्रिप्ट मोंगोडब द्वारा प्रदान किए गए देशी ऑपरेटरों की तुलना में अधिक धीरे-धीरे निष्पादित होता है, लेकिन यह बहुत लचीला है। देखें: stackoverflow.com/a/7811259/2893073 , तो अंतिम समाधान है: stackoverflow.com/a/15224544/2893073
एड़ी

26

नियमित क्वेरी में एकत्रीकरण कार्यों का उपयोग करने के लिए आप $ expr (3.6 mongo संस्करण ऑपरेटर) का उपयोग कर सकते हैं ।

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
@DanDascalescu ऐसा लगता है कि सभी दस्तावेजों में डाक टिकट मौजूद नहीं है। स्टैम्प के मौजूद न होने पर आप खाली सरणी को आउटपुट करने के लिए ifNull का उपयोग कर सकते हैं । कुछ इस तरहdb.col.find({$expr:{$gt:[{$size:{$ifNull:["$passport.stamps", []]}}, 1]}})
सागर वीरम


22

MongoDB 3.6 में $ expr https://docs.mongodb.com/manual/reference/operator/query/expr/ शामिल हैं

$ मिलान के अंदर किसी अभिव्यक्ति का मूल्यांकन करने या खोजने के लिए आप $ 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 और $ size के साथ कोशिश कर रहा हूं। मुझे लगता है कि खोजने के लिए () तेजी से है।

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

-5

यद्यपि उपरोक्त सभी कार्यों का उत्तर देता है, आपने मूल रूप से जो करने की कोशिश की थी, वह सही तरीका था, हालांकि आपके पास सिंटैक्स पीछे की ओर है (स्विच "$ आकार" और "$ gt") ..

सही बात:

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

गलत:

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

1
मैं यह नहीं देखता कि इतने सारे पतन क्यों हुए - यह मेरे लिए पूरी तरह से काम करता है!
जेक स्टोक्स

मैंने नीचा नहीं देखा, लेकिन यह काम नहीं करता है (v4.2)।
इवगेनी नाबोकोव

पूरी तरह से ठीक काम करता है, v 4.2.5
jperl
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.