Apa sintaks untuk melakukan $ lookup pada bidang yang merupakan larik ObjectIds daripada hanya satu ObjectId?
Contoh Dokumen Pemesanan:
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
]
}
Kueri Tidak Berfungsi:
db.orders.aggregate([
{
$lookup:
{
from: "products",
localField: "products",
foreignField: "_id",
as: "productObjects"
}
}
])
Hasil yang diinginkan
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
],
productObjects: [
{<Car Object>},
{<Bike Object>}
],
}
mongodb
mongodb-query
aggregation-framework
Jason Lin
sumber
sumber
Jawaban:
Pembaruan 2017
$ lookup sekarang bisa langsung menggunakan array sebagai field lokal .
$unwind
tidak lagi dibutuhkan.Jawaban lama
Tahap
$lookup
pipeline agregasi tidak akan bekerja secara langsung dengan array. Maksud utama dari desain ini adalah untuk "gabungan kiri" sebagai jenis gabungan "satu ke banyak" (atau sebenarnya "pencarian") pada data terkait yang mungkin. Tetapi nilainya dimaksudkan untuk menjadi tunggal dan bukan sebuah array.Oleh karena itu, Anda harus "membatalkan normalisasi" konten terlebih dahulu sebelum melakukan
$lookup
operasi agar ini berfungsi. Dan itu berarti menggunakan$unwind
:Setelah
$lookup
cocok setiap anggota array, hasilnya adalah array itu sendiri, jadi Anda$unwind
kembali dan$group
ke$push
array baru untuk hasil akhir.Perhatikan bahwa setiap kecocokan "left join" yang tidak ditemukan akan membuat array kosong untuk "productObjects" pada produk yang diberikan dan dengan demikian meniadakan dokumen untuk elemen "product" ketika yang kedua
$unwind
dipanggil.Meskipun aplikasi langsung ke array akan bagus, hanya saja cara kerjanya saat ini dengan mencocokkan nilai singular ke banyak kemungkinan.
Seperti
$lookup
pada dasarnya sangat baru, saat ini bekerja seperti yang biasa bagi mereka yang akrab dengan luwak sebagai "versi orang miskin" dari.populate()
metode yang ditawarkan di sana. Perbedaannya adalah bahwa$lookup
menawarkan "sisi server" pemrosesan "bergabung" sebagai lawan pada klien dan bahwa beberapa "kematangan" dalam$lookup
saat ini kurang dari apa yang.populate()
ditawarkan (seperti interpolasi pencarian langsung pada array).Ini sebenarnya adalah masalah yang ditugaskan untuk perbaikan SERVER-22881 , jadi dengan sedikit keberuntungan ini akan mengenai rilis berikutnya atau segera setelahnya.
Sebagai prinsip desain, struktur Anda saat ini tidak baik atau buruk, tetapi hanya dikenakan biaya tambahan saat membuat "sambungan" apa pun. Dengan demikian, prinsip berdiri dasar MongoDB di awal berlaku, di mana jika Anda "dapat" hidup dengan data "pra-bergabung" dalam satu koleksi, maka yang terbaik adalah melakukannya.
Satu hal lagi yang dapat dikatakan
$lookup
sebagai prinsip umum, adalah bahwa maksud dari "bergabung" di sini adalah untuk bekerja sebaliknya daripada yang ditunjukkan di sini. Jadi, daripada menyimpan "id terkait" dari dokumen lain di dalam dokumen "induk", prinsip umum yang bekerja paling baik adalah di mana "dokumen terkait" berisi referensi ke "induk".Jadi
$lookup
dapat dikatakan "bekerja paling baik" dengan "desain relasi" yang merupakan kebalikan dari bagaimana sesuatu seperti luwak.populate()
melakukan penggabungan sisi kliennya. Dengan idendifikasi "satu" dalam setiap "banyak", maka Anda cukup menarik item terkait tanpa perlu ke$unwind
array terlebih dahulu.sumber
$lookup
dan validasi Dokumen sebagai fitur dalam masa pertumbuhan dan cenderung meningkat. Jadi, perluasan langsung pada larik akan disambut, seperti halnya "kueri" untuk memfilter hasil. Keduanya akan jauh lebih selaras dengan.populate()
proses luwak yang biasa dilakukan banyak orang. Menambahkan tautan masalah langsung ke konten jawaban.$lookup
sekarang berfungsi langsung pada array.Dimulai dengan MongoDB v3.4 (dirilis pada 2016),
$lookup
tahap pipeline agregasi juga dapat berfungsi langsung dengan array . Tidak perlu$unwind
lagi.Ini dilacak di SERVER-22881 .
sumber
Anda juga bisa menggunakan
pipeline
dekor untuk melakukan pemeriksaan pada larik sub-dokumenBerikut contoh penggunaan
python
(maaf saya orang ular).Tangkapan di sini adalah untuk mencocokkan semua objek di
ObjectId
array
(asing_id
yang ada dilocal
bidang / penyanggaproducts
).Anda juga dapat membersihkan atau memproyeksikan catatan asing dengan tambahan
stage
, seperti yang ditunjukkan oleh komentar di atas.sumber
gunakan $ unwind Anda akan mendapatkan objek pertama, bukan array objek
pertanyaan:
hasil:
sumber
Menggabungkan dengan
$lookup
dan berikutnya$group
cukup rumit, jadi jika (dan itu media jika) Anda menggunakan node & Mongoose atau pustaka pendukung dengan beberapa petunjuk dalam skema, Anda dapat menggunakan a.populate()
untuk mengambil dokumen-dokumen itu:sumber
Saya harus tidak setuju, kita dapat membuat $ lookup berfungsi dengan array ID jika kita mengawali dengan $ match stage.
Ini menjadi lebih rumit jika kita ingin meneruskan hasil pencarian ke pipeline. Tetapi sekali lagi ada cara untuk melakukannya (sudah disarankan oleh @ user12164):
sumber