Pembaruan 2017
$lookup sekarang dapat langsung menggunakan array sebagai bidang lokal. $unwind
tidak diperlukan lagi.
Jawaban lama
$lookup
tahap pipa agregasi tidak akan bekerja secara langsung dengan array. Maksud utama dari desain ini adalah untuk "gabung kiri" sebagai jenis gabungan "satu ke banyak" (atau benar-benar "pencarian") pada kemungkinan data terkait. Tapi nilainya dimaksudkan untuk menjadi tunggal dan bukan array.
Oleh karena itu Anda harus "menormalkan kembali" konten terlebih dahulu sebelum melakukan $lookup
operasi agar ini bekerja. Dan itu berarti menggunakan $unwind
:
db.orders.aggregate([
// Unwind the source
{ "$unwind": "$products" },
// Do the lookup matching
{ "$lookup": {
"from": "products",
"localField": "products",
"foreignField": "_id",
"as": "productObjects"
}},
// Unwind the result arrays ( likely one or none )
{ "$unwind": "$productObjects" },
// Group back to arrays
{ "$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"productObjects": { "$push": "$productObjects" }
}}
])
Setelah $lookup
cocok dengan setiap anggota larik, hasilnya adalah larik itu sendiri, jadi Anda $unwind
lagi dan $group
ke $push
array baru untuk hasil akhir.
Perhatikan bahwa setiap kecocokan "gabung kiri" yang tidak ditemukan akan membuat larik kosong untuk "productObjects" pada produk yang diberikan dan dengan demikian meniadakan dokumen untuk elemen "produk" saat $unwind
kedua disebut.
Meskipun aplikasi langsung ke array akan menyenangkan, ini hanya cara kerjanya saat ini dengan mencocokkan nilai tunggal ke banyak kemungkinan.
Sebagai $lookup
pada dasarnya sangat baru, saat ini berfungsi seperti biasa bagi mereka yang akrab dengan luwak sebagai "versi orang miskin" dari .populate()
metode yang ditawarkan di sana. Perbedaannya adalah $lookup
menawarkan pemrosesan "sisi server" dari "gabung" sebagai lawan dari pada klien dan bahwa beberapa "kematangan" di $lookup
saat ini kurang dari apa .populate()
menawarkan ( seperti interpolasi pencarian langsung pada array ).
Ini sebenarnya adalah masalah yang ditetapkan untuk peningkatan SERVER-22881, jadi dengan sedikit keberuntungan ini akan mencapai rilis berikutnya atau segera setelahnya.
Sebagai prinsip desain, struktur Anda saat ini tidak baik atau buruk, tetapi hanya dikenakan biaya tambahan saat membuat "gabungan" apa pun. Dengan demikian, prinsip dasar MongoDB di awal berlaku, di mana jika Anda "bisa" hidup dengan data "pra-bergabung" dalam satu koleksi, maka yang terbaik adalah melakukannya.
Satu hal lagi yang dapat dikatakan tentang $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 paling berhasil adalah jika "dokumen terkait" berisi referensi ke "induk".
Jadi $lookup
dapat dikatakan "bekerja paling baik" dengan "desain hubungan" yang merupakan kebalikan dari bagaimana sesuatu seperti luwak .populate()
melakukan itu sisi klien bergabung. Dengan mengidentifikasi "satu" di dalam setiap "banyak", maka Anda cukup menarik item terkait tanpa perlu $unwind
array terlebih dahulu.