Temukan dokumen dengan larik yang berisi nilai tertentu

499

Jika saya memiliki skema ini ...

person = {
    name : String,
    favoriteFoods : Array
}

... di mana favoriteFoodsarray diisi dengan string. Bagaimana saya bisa menemukan semua orang yang menggunakan "sushi" sebagai makanan favorit mereka menggunakan luwak?

Saya berharap sesuatu seperti:

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

(Saya tahu bahwa tidak ada $containsdalam mongodb, hanya menjelaskan apa yang saya harapkan sebelum mengetahui solusinya)

Ludwig Magnusson
sumber

Jawaban:

693

Seperti favouriteFoodsarray string sederhana, Anda bisa langsung menanyakan bidang itu:

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

Tetapi saya juga merekomendasikan untuk membuat array string secara eksplisit dalam skema Anda:

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

Dokumentasi yang relevan dapat ditemukan di sini: https://docs.mongodb.com/manual/tutorial/query-arrays/

JohnnyHK
sumber
19
Ini juga berfungsi jika favouriteFoods:favouriteFoods:[{type:Schema.Types.ObjectId, ref:'Food'}]
k88074
12
Sebagai orang baru di Mongo yang datang dari RDBMS seperti MySQL, untuk menemukan bahwa solusi seperti itu berfungsi begitu sederhana tanpa perlu BERGABUNG dan tabel tambahan membuat saya bertanya-tanya mengapa saya belum mulai menggunakan Mongo lebih awal. Tetapi itu tidak berarti bahwa DBMS lebih baik dari yang lain - itu tergantung pada kasus penggunaan Anda.
Irvin Lim
9
Jangan salah. Bahkan jika itu adalah daftar dict, Anda masih dapat menanyakannya dengan cara ini. Contoh: PersonModel.find({ favouriteFoods.text: "sushi" }, ...); person = { name : String, favouriteFoods : [{text:String}] }
Aminah Nuraini
3
Apa yang terjadi ketika saya ingin menemukan Array yang berisi setidaknya dua string?
Aero Wang
151

Tidak ada $containsoperator di mongodb.

Anda dapat menggunakan jawaban dari JohnnyHK karena berfungsi. Analogi terdekat yang mengandung mongo adalah $in, menggunakan kueri Anda akan terlihat seperti:

PersonModel.find({ favouriteFoods: { "$in" : ["sushi"]} }, ...);
Alistair Nelson
sumber
10
Apakah ini benar? Bukankah mongodb mengharapkan array nilai saat menggunakan $ in? seperti {name: {$ in: ["Paul", "Dave", "Larry", "Adam"]}}?
Ludwig Magnusson
38
Hah? Ini tidak perlu. $indigunakan ketika Anda memiliki beberapa nilai kueri dan dokumen harus cocok dengan salah satunya. Untuk kebalikannya (yang merupakan pertanyaan ini), jawaban JohnnyHK benar. Saya akan mengundurkan diri tetapi saya kira jawaban ini mungkin bermanfaat bagi orang lain yang berakhir di halaman ini.
MalcolmOcean
4
Tapi ini membantu saya untuk benar-benar bertanya dengan beberapa nilai: D Terima kasih banyak!
Alexandre Bourlier
11
Terima kasih. Inilah yang sebenarnya saya cari, cara mencari beberapa nilai:PersonModel.find({favouriteFoods: {"$in": ["sushi", "hotdog"]}})
totymedli
@ MalcolmOcean benar, bahwa operator $ in adalah sebaliknya, memiliki array sebagai nilainya . The lapangan menjadi sebuah array adalah apa pertanyaannya adalah bertanya tentang. Namun, jika kedua bidang dan nilai adalah array, maka kedua jawaban ini dan JohnnyHK ini relevan, berarti Anda lakukan perlu $ di.
tscizzle
88

Saya merasa $allakan lebih cocok dalam situasi ini. Jika Anda mencari orang yang suka sushi, Anda lakukan:

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

Karena Anda mungkin ingin memfilter lebih banyak pencarian Anda, seperti:

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

$inseperti ATAU dan $allseperti DAN. Periksa ini: https://docs.mongodb.com/manual/reference/operator/query/all/

Pobe
sumber
Maaf, ini jawaban yang salah untuk pertanyaan saya. Saya tidak mencari kecocokan persis tetapi hanya untuk array yang mengandung setidaknya nilai yang ditentukan.
Ludwig Magnusson
18
Ini adalah jawaban yang benar-benar valid untuk pertanyaan Anda! Untuk satu nilai tidak ada perbedaan dalam menggunakan $ all atau $ in. Jika Anda memiliki beberapa nilai seperti "sushi", "pisang", $ all mencari orang yang memiliki "sushi" DAN "pisang" di deretan Makanan favorit mereka, jika menggunakan $ di Anda mendapatkan orang yang memiliki "sushi" ATAU "pisang" "Dalam susunan makanan favorit mereka.
Jodo
ya, tidak ada $ berisi tetapi $ semua adalah semacam itu
datdinhquoc
3
Jawaban terbaik
Nikolay Tsenkov
65

Dalam hal array berisi objek misalnya jika favouriteFoodsarray objek berikut ini:

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

Anda dapat menggunakan kueri berikut:

PersonModel.find({"favouriteFoods.name": "Sushi"});
Kfir Erez
sumber
2
Ini dengan mudah jawaban terbaik. Jauh lebih mudah digunakan saat Anda sedang terburu-buru.
Uber Schnoz
Ini harus menjadi jawaban yang dipilih. Jika Anda berurusan dengan kueri array dokumen bersarang di MongoDB, ini adalah bagaimana Anda melakukannya. Tidak yakin apakah ini yang paling efisien, tetapi jika hanya itu yang Anda coba lakukan, inilah yang Anda butuhkan.
Kyle L.
32

Jika Anda perlu menemukan dokumen yang berisi elemen NULL di dalam array sub-dokumen, saya telah menemukan kueri ini yang bekerja dengan cukup baik:

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

Kueri ini diambil dari posting ini: Array kueri MongoDb dengan nilai nol

Itu adalah penemuan yang hebat dan bekerja jauh lebih baik daripada versi awal dan salah saya sendiri (yang ternyata berfungsi dengan baik hanya untuk array dengan satu elemen):

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

Meskipun setuju dengan find () paling efektif di usecase Anda. Masih ada $ match of aggregation framework, untuk mempermudah permintaan sejumlah besar entri dan menghasilkan sejumlah kecil hasil yang menyimpan nilai bagi Anda terutama untuk mengelompokkan dan membuat file baru.

  PersonModel.aggregate([
            { 
                 "$match": { 
                     $and : [{ 'favouriteFoods' : { $exists: true, $in: [ 'sushi']}}, ........ ]  }
             },
             { $project : {"_id": 0, "name" : 1} }
            ]);
Amitesh
sumber
tidak bekerja dengan mongodb 4.2 .. harap balas
vimmi
Kesalahan apa yang Anda dapatkan, harap berikan secara detail?
Amitesh
3

Memetikan lookup_food_array adalah array.

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

Memetikan lookup_food_array adalah string.

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

Untuk Loopback3 semua contoh yang diberikan tidak bekerja untuk saya, atau secepat menggunakan REST API. Tetapi itu membantu saya menemukan jawaban tepat yang saya butuhkan.

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

Mark Ryan Orosa
sumber
1
Anda adalah penyelamat, terima kasih! Di mana itu didokumentasikan dan saya melewatkannya? Bisakah Anda memposting tautannya? Terima kasih.
user2078023
-3

Jika Anda ingin menggunakan sesuatu seperti operator "berisi" melalui javascript, Anda selalu dapat menggunakan ekspresi Reguler untuk itu ...

misalnya. Katakanlah Anda ingin mengambil pelanggan yang memiliki "Bartolomew" sebagai nama

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);
}
Alingenomen
sumber
-26

Saya tahu topik ini sudah tua, tetapi untuk orang-orang masa depan yang dapat bertanya-tanya pertanyaan yang sama, solusi lain yang sangat tidak efisien adalah dengan:

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

Ini menghindari semua optimisasi oleh MongoDB jadi jangan gunakan dalam kode produksi.

pengguna3027146
sumber
Karena penasaran, apakah ada manfaat melakukannya dengan cara ini?
Ludwig Magnusson
5
Ini sangat tidak efisien dibandingkan dengan jawaban yang diterima; ia menghindari semua pengoptimalan yang dilakukan Mongo di belakang layar untuk mendapatkan temuan langsung seperti yang diterima.
tanpa disadari
1
Ini persis jawaban yang saya butuhkan dalam kasus saya! Terima kasih "pengguna" :)
Vasyl Boroviak