Semua catatan saya memiliki bidang yang disebut "gambar". Bidang ini adalah larik string.
Saya sekarang ingin 10 catatan terbaru di mana array ini TIDAK kosong.
Saya sudah googled sekitar, tapi anehnya saya belum menemukan banyak tentang ini. Saya sudah membaca opsi $ where, tapi saya bertanya-tanya seberapa lambat itu untuk fungsi asli, dan jika ada solusi yang lebih baik.
Dan bahkan kemudian, itu tidak berhasil:
ME.find({$where: 'this.pictures.length > 0'}).sort('-created').limit(10).execFind()
Tidak menghasilkan apa-apa. Meninggalkan this.pictures
tanpa panjang bit tidak berfungsi, tetapi kemudian juga mengembalikan catatan kosong, tentu saja.
mongoengine
ME.find({ pictures: { $gt: [] } })
BERBAHAYA, bahkan dalam versi MongoDB yang lebih baru. Jika Anda memiliki indeks pada bidang daftar Anda dan indeks itu digunakan selama permintaan, Anda akan mendapatkan hasil yang tidak terduga. Misalnya:db.doc.find({'nums': { $gt: [] }}).hint({ _id: 1 }).count()
mengembalikan nomor yang benar, sementaradb.doc.find({'nums': { $gt: [] }}).hint({ nums: 1 }).count()
mengembalikan0
.Setelah beberapa mencari lagi, terutama di dokumen mongodb, dan membingungkan bit, ini jawabannya:
sumber
pictures
bidang.Ini juga bisa bekerja untuk Anda:
sumber
pictures.2
ada tetapipictures.1
tidak?$exists
operator adalah boolean, bukan offset. @tenbatsu harus menggunakantrue
bukan1
.Would there ever be a case where pictures.2 exists but pictures.1 does not?
Ya, kasus itu bisa terjadi.pictures
merupakan sub-doc, bukan array misalnyapictures: {'2': 123}
pictures
.Anda peduli pada dua hal saat mengajukan pertanyaan - akurasi dan kinerja. Dengan pemikiran itu, saya menguji beberapa pendekatan berbeda dalam MongoDB v3.0.14.
TL; DR
db.doc.find({ nums: { $gt: -Infinity }})
adalah yang tercepat dan paling dapat diandalkan (setidaknya dalam versi MongoDB yang saya uji).EDIT: Ini tidak lagi berfungsi di MongoDB v3.6! Lihat komentar di bawah posting ini untuk solusi potensial.
Mendirikan
Saya memasukkan dokumen 1k tanpa kolom daftar, dokumen 1k dengan daftar kosong, dan 5 dokumen dengan daftar tidak kosong.
Saya menyadari ini bukan skala yang cukup untuk menganggap kinerja seserius saya dalam tes di bawah ini, tetapi cukup untuk menyajikan kebenaran berbagai pertanyaan dan perilaku rencana kueri yang dipilih.
Tes
db.doc.find({'nums': {'$exists': true}})
mengembalikan hasil yang salah (untuk apa yang ingin kami capai).-
db.doc.find({'nums.0': {'$exists': true}})
mengembalikan hasil yang benar, tetapi juga lambat menggunakan pemindaian koleksi penuh (COLLSCAN
tahap pemberitahuan dalam penjelasan).-
db.doc.find({'nums': { $exists: true, $gt: { '$size': 0 }}})
mengembalikan hasil yang salah. Itu karena pemindaian indeks tidak valid memajukan tidak ada dokumen. Kemungkinan akan akurat tetapi lambat tanpa indeks.-
db.doc.find({'nums': { $exists: true, $not: { '$size': 0 }}})
mengembalikan hasil yang benar, tetapi kinerjanya buruk. Secara teknis melakukan pemindaian indeks, tetapi kemudian masih memajukan semua dokumen dan kemudian harus menyaring melalui mereka).-
db.doc.find({'nums': { $exists: true, $ne: [] }})
mengembalikan hasil yang benar dan sedikit lebih cepat, tetapi kinerjanya masih tidak ideal. Ia menggunakan IXSCAN yang hanya memajukan dokumen dengan bidang daftar yang ada, tetapi kemudian harus menyaring daftar kosong satu per satu.-
db.doc.find({'nums': { $gt: [] }})
IS BERBAHAYA KARENA BERGANTUNG PADA INDEKS YANG DIGUNAKAN, MUNGKIN MEMBERIKAN HASIL YANG TIDAK DIKENALKAN. Itu karena pemindaian indeks yang tidak valid yang tidak memajukan dokumen.-
db.doc.find({'nums.0’: { $gt: -Infinity }})
mengembalikan hasil yang benar, tetapi memiliki kinerja buruk (menggunakan pemindaian koleksi penuh).-
db.doc.find({'nums': { $gt: -Infinity }})
Yang mengejutkan, ini bekerja dengan sangat baik! Ini memberikan hasil yang tepat dan cepat, memajukan 5 dokumen dari fase pemindaian indeks.sumber
seen_events
array String, yang juga diindeks. Mencari dengan{ $gt: -Infinity }
, saya langsung mendapatkan 0 dokumen. Menggunakan{ $exists: true, $ne: [] }
I mendapatkan dokumen 1,2m lebih mungkin, dengan banyak waktu terbuang dalam tahap FETCH: gist.github.com/N-Coder/b9e89a925e895c605d84bfeed648d82cdb.test_collection.find({"seen_events.0": {$exists: true}})
buruk karena menggunakan pemindaian koleksi. 2.db.test_collection.find({seen_events: {$exists: true, $ne: []}})
adalah buruk karena IXSCAN-nya cocok dengan semua dokumen dan kemudian penyaringan dilakukan dalam fase FETCH lambat 3. Sama berlaku untukdb.test_collection.find({seen_events: {$exists: true, $not: {$size: 0}}})
4. Semua pertanyaan lain mengembalikan hasil yang tidak validseen_events
mengandung string, Anda dapat menggunakan ini:db.test_collection.find({seen_events: {$gt: ''}}).count()
. Untuk mengonfirmasi itu berfungsi dengan baik, periksadb.test_collection.find({seen_events: {$gt: ''}}).explain(true).executionStats
. Anda mungkin dapat menegakkan bahwa peristiwa yang terlihat adalah string melalui validasi skema: docs.mongodb.com/manual/core/schema-validationDimulai dengan rilis 2.6, cara lain untuk melakukan ini adalah membandingkan bidang ke array kosong:
Mengujinya di shell:
Jadi ia dengan benar menyertakan dokumen yang
pictures
memiliki setidaknya satu elemen array, dan mengecualikan dokumen yangpictures
merupakan array kosong, bukan array, atau hilang.sumber
db.ME.createIndex({ pictures: 1 })
dan kemudiandb.ME.find({pictures: {$gt: []}})
akan mengembalikan hasil nol, setidaknya di MongoDB v3.0.14Anda dapat menggunakan salah satu dari yang berikut untuk mencapai ini.
Keduanya juga berhati-hati agar tidak mengembalikan hasil untuk objek yang tidak memiliki kunci yang diminta di dalamnya:
sumber
Ambil semua dan hanya dokumen di mana 'gambar' adalah larik dan tidak kosong
Jika menggunakan versi MongoDb sebelum 3.2 , gunakan
$type: 4
sebagai ganti$type: 'array'
. Perhatikan bahwa solusi ini bahkan tidak menggunakan $ size , jadi tidak ada masalah dengan indeks ("Kueri tidak dapat menggunakan indeks untuk bagian $ size dari kueri")Solusi lain, termasuk ini (jawaban yang diterima):
adalah salah karena mereka kembali dokumen bahkan jika, misalnya, 'gambar' adalah
null
,undefined
, 0, dllsumber
Gunakan
$elemMatch
operator: sesuai dengan dokumentasi$elemMatches
memastikan bahwa nilainya adalah array dan tidak kosong. Jadi kueri akan seperti ituME.find({ pictures: { $elemMatch: {$exists: true }}})
PS Varian dari kode ini ditemukan dalam kursus M121 Universitas MongoDB.
sumber
Anda juga dapat menggunakan metode helper Ada di atas operator Mongo $ ada
sumber
gunakan $ mana dan lewati this.field_name.length yang mengembalikan ukuran bidang array dan memeriksanya dengan membandingkan dengan angka. jika setiap array memiliki nilai lebih dari ukuran array harus minimal 1. jadi semua field array memiliki panjang lebih dari satu, itu berarti ia memiliki beberapa data dalam array itu
sumber
Sesederhana itu, ini berhasil untuk saya.
sumber