Belirli bir değer içeren diziye sahip belgeyi bulma


499

Bu şemam varsa ...

person = {
    name : String,
    favoriteFoods : Array
}

... favoriteFoodsdizenin dizelerle doldurulduğu yer. Firavun faresi kullanan "suşi" ye sahip olan tüm insanları mongoose kullanarak nasıl bulabilirim?

Aşağıdakiler boyunca bir şey umuyordum:

PersonModel.find({ favoriteFoods : { $contains : "sushi" }, function(...) {...});

( $containsMongodb'da kimse olmadığını biliyorum , sadece çözümü bilmeden önce ne beklediğimi açıklıyorum)

Yanıtlar:


693

favouriteFoodsBasit bir dize dizisi olduğu gibi , bu alanı doğrudan sorgulayabilirsiniz:

PersonModel.find({ favouriteFoods: "sushi" }, ...);

Ama aynı zamanda dize dizisini şemanızda açık hale getirmenizi de tavsiye ederim:

person = {
    name : String,
    favouriteFoods : [String]
}

İlgili belgeleri burada bulabilirsiniz: https://docs.mongodb.com/manual/tutorial/query-arrays/


19
Bu favouriteFoodsşu durumlarda da işe yarar :favouriteFoods:[{type:Schema.Types.ObjectId, ref:'Food'}]
k88074

12
MySQL gibi bir RDBMS'den gelen Mongo'da yeni biri olarak, bu tür çözümlerin JOIN'lere ve ek tablolara ihtiyaç duymadan bu kadar basit çalıştığını bulmak, neden Mongo'da daha önce başlamadığımı merak ediyor. Ancak bu, her iki DBMS'nin diğerinden daha üstün olduğu anlamına gelmez - kullanım durumunuza bağlıdır.
Irvin Lim

9
Hata yapma. Bir dikte listesi olsa bile, yine de bu şekilde sorgulayabilirsiniz. Örnek: PersonModel.find({ favouriteFoods.text: "sushi" }, ...); person = { name : String, favouriteFoods : [{text:String}] }
Aminah Nuraini

3
En az iki dize içeren bir Dizi bulmak istediğimde ne olur?
Aero Wang

151

$containsMongodb'da operatör yok .

Çalıştığı gibi JohnnyHK'nın cevabını kullanabilirsiniz. Mongo'nun içerdiği en yakın benzetme, bunu $inkullanarak sorgunuz şöyle görünecektir:

PersonModel.find({ favouriteFoods: { "$in" : ["sushi"]} }, ...);

10
Bu doğru mu? Mongodb $ in kullanılırken bir değer dizisi beklemiyor mu? {name: {$ in: ["Paul", "Dave", "Larry", "Adam"]}} gibi mi?
Ludwig Magnusson

37
Ha? Bu gereksiz. $inbirden çok sorgu değeriniz olduğunda ve belgenin bunlardan biriyle eşleşmesi gerektiğinde kullanılır. Tersine (bu sorunun ne olduğu), JohnnyHK'nın cevabı doğrudur. Ben aşağıya gidecektim ama sanırım bu cevap bu sayfaya ulaşan diğer insanlar için yararlı olabilir.
MalcolmOcean

4
Ama bu aslında birkaç değerle sorgulamama yardımcı oldu: D Çok teşekkürler!
Alexandre Bourlier

10
Teşekkürler. Aslında aradığım şey, birden çok değer aramanın yolu:PersonModel.find({favouriteFoods: {"$in": ["sushi", "hotdog"]}})
totymedli

@MalcolmOcean, $ in operatörünün tersi olması ve değer olarak bir diziye sahip olması nedeniyle doğrudur . Dizi olan alan , sorunun sorduğu şeydir. Ancak, hem alan hem de değer diziyse, hem bu cevap hem de JohnnyHK'lar alakalı, yani $ in'e ihtiyacınız var demektir.
tscizzle

87

$allBu durumda daha uygun olacağını hissediyorum . Eğer suşi içine kişi arıyorsanız yapmak:

PersonModel.find({ favoriteFood : { $all : ["sushi"] }, ...})

Aramanıza daha fazla filtre uygulamak isteyebileceğinizden, şöyle:

PersonModel.find({ favoriteFood : { $all : ["sushi", "bananas"] }, ...})

$inOR $allgibi ve AND gibi. Bunu kontrol edin: https://docs.mongodb.com/manual/reference/operator/query/all/


Üzgünüm, bu sorumun cevabı yanlış. Tam bir eşleşme değil, sadece en azından belirtilen değeri içeren diziler için arıyorum.
Ludwig Magnusson

17
Bu, sorunuz için tamamen geçerli bir cevaptır! Bir değer için $ all veya $ in kullanmanın bir farkı yoktur. Eğer "suşi", "muz" gibi çeşitli değerleriniz varsa, $ all, favori yemeklerinde "suşi" VE "muz" olan kişileri arıyor, eğer $ kullanarak "suşi" VEYA "muzları olan kişiler alıyorsanız "En sevdikleri yiyecek dizisinde.
Jodo

evet, $ yok ama $ hepsi öyle
datdinhquoc

2
En iyi cevap.
Nikolay Tsenkov

65

Dizinin nesneler içermesi durumunda favouriteFoods, örneğin aşağıdakilerden oluşan bir nesne dizisi ise:

{
  name: 'Sushi',
  type: 'Japanese'
}

aşağıdaki sorguyu kullanabilirsiniz:

PersonModel.find({"favouriteFoods.name": "Sushi"});

2
Bu kolayca en iyi cevaptır. Aceleniz olduğunda kullanmak çok daha kolay.
Uber Schnoz

Bu seçilen cevap olmalıdır. MongoDB'de bir dizi iç içe belge sorgulamakla uğraşıyorsanız, bunu böyle yaparsınız. En verimli olup olmadığından emin değilim ama yapmaya çalıştığınız tek şey buysa, ihtiyacınız olan tek şey bu.
Kyle L.

32

Bir dizi alt belge içinde NULL öğeler içeren belgeleri bulmanız gerekirse, oldukça iyi çalışan bu sorguyu buldum:

db.collection.find({"keyWithArray":{$elemMatch:{"$in":[null], "$exists":true}}})

Bu sorgu şu yayından alınmıştır: null değerleri olan MongoDb sorgu dizisi

Harika bir keşifti ve kendi başlangıç ve yanlış sürümümden çok daha iyi çalışıyor (bu sadece bir öğeye sahip diziler için iyi sonuç verdi):

.find({
    'MyArrayOfSubDocuments': { $not: { $size: 0 } },
    'MyArrayOfSubDocuments._id': { $exists: false }
})

3

Rağmen find () ile usecase en etkili olduğunu kabul. Yine de, çok sayıda girişin sorgusunu kolaylaştırmak ve özellikle yeni dosyaları gruplamak ve oluşturmak için size değer veren düşük sayıda sonuç üretmek için toplama çerçevesinin $ eşleşmesi vardır.

  PersonModel.aggregate([
            { 
                 "$match": { 
                     $and : [{ 'favouriteFoods' : { $exists: true, $in: [ 'sushi']}}, ........ ]  }
             },
             { $project : {"_id": 0, "name" : 1} }
            ]);

mongodb 4.2 ile çalışmıyor ... lütfen cevap verin
vimmi

Ne hata alıyorsunuz, lütfen ayrıntılı olarak verin?
Amitesh

3

Lookup_food_array olayı dizidir.

match_stage["favoriteFoods"] = {'$elemMatch': {'$in': lookup_food_array}}

Lookup_food_array öğesi dizedir.

match_stage["favoriteFoods"] = {'$elemMatch': lookup_food_string}

1

Loopback3 için verilen tüm örnekler benim için ya da REST API'yi kullanmak kadar hızlı olmadı. Ama tam olarak ihtiyacım olan cevabı bulmama yardımcı oldu.

{"where":{"arrayAttribute":{ "all" :[String]}}}


1
Hayat kurtarıcısın, teşekkürler! Nerede belgeleniyor ve kaçırdım? Bağlantıyı gönderebilir misiniz lütfen? Teşekkürler.
user2078023

-3

Javascript aracılığıyla "içerir" operatörü gibi bir şey kullanmak isterseniz, bunun için her zaman düzenli bir ifade kullanabilirsiniz ...

Örneğin. Diyelim ki "Bartolomew" sahibi bir müşteriyi

async function getBartolomew() {
    const custStartWith_Bart = await Customers.find({name: /^Bart/ }); // Starts with Bart
    const custEndWith_lomew = await Customers.find({name: /lomew$/ }); // Ends with lomew
    const custContains_rtol = await Customers.find({name: /.*rtol.*/ }); // Contains rtol

    console.log(custStartWith_Bart);
    console.log(custEndWith_lomew);
    console.log(custContains_rtol);
}

-26

Bu konunun eski olduğunu biliyorum, ancak aynı soruyu merak edebilecek gelecekteki insanlar için inanılmaz derecede verimsiz bir çözüm daha yapmak olabilir:

PersonModel.find({$where : 'this.favouriteFoods.indexOf("sushi") != -1'});

Bu, MongoDB'nin tüm optimizasyonlarını önler, bu nedenle üretim kodunda kullanmayın.


Meraktan, bu şekilde yapmanın bir avantajı var mı?
Ludwig Magnusson

5
Bu, kabul edilen cevaba kıyasla inanılmaz derecede verimsizdir; Mongo'nun kabul edilen gibi düz bir bulmak için perde arkasına koyduğu tüm optimizasyonu atlatır.
kasıtsız

1
Bu tam da benim durumumda ihtiyacım olan cevap! Teşekkür ederim "kullanıcı" :)
Vasyl Boroviak
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.