MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Cara bergabung ke dua koleksi tambahan dengan ketentuan

Apa yang Anda lewatkan di sini adalah $lookup menghasilkan "array" di bidang keluaran yang ditentukan oleh as dalam argumennya. Ini adalah konsep umum "hubungan" MongoDB, di mana "hubungan" antara dokumen direpresentasikan sebagai "sub-properti" yang "di dalam" dokumen itu sendiri, baik tunggal atau "array" bagi banyak orang.

Karena MongoDB "tanpa skema", anggapan umum $lookup adalah yang Anda maksud "banyak" dan hasilnya adalah "selalu" sebuah array. Jadi mencari "hasil yang sama seperti di SQL" maka Anda perlu $unwind array itu setelah $lookup . Apakah itu "satu" atau "banyak" tidak ada artinya, karena masih "selalu" sebuah array:

db.getCollection.('tb1').aggregate([
  // Filter conditions from the source collection
  { "$match": { "status": { "$ne": "closed" } }},

  // Do the first join
  { "$lookup": {
    "from": "tb2",
    "localField": "id",
    "foreignField": "profileId",
    "as": "tb2"
  }},

  // $unwind the array to denormalize
  { "$unwind": "$tb2" },

  // Then match on the condtion for tb2
  { "$match": { "tb2.profile_type": "agent" } },

  // join the second additional collection
  { "$lookup": {
    "from": "tb3",
    "localField": "tb2.id",
    "foreignField": "id",
    "as": "tb3"
  }},

  // $unwind again to de-normalize
  { "$unwind": "$tb3" },

  // Now filter the condition on tb3
  { "$match": { "tb3.status": 0 } },

  // Project only wanted fields. In this case, exclude "tb2"
  { "$project": { "tb2": 0 } }
])

Di sini Anda perlu mencatat hal-hal lain yang Anda lewatkan dalam terjemahan:

Urutan itu "penting"

Pipa agregasi lebih "sangat ekspresif" daripada SQL. Mereka sebenarnya paling baik dianggap sebagai "urutan langkah" diterapkan ke sumber data untuk menyusun dan mengubah data. Analog terbaik untuk ini adalah instruksi baris perintah "piped", seperti:

ps -ef  | grep mongod | grep -v grep | awk '{ print $1 }'

Dimana "pipa" | dapat dianggap sebagai "tahap pipa" dalam "pipa" agregasi MongoDB.

Karena itu kami ingin $match untuk memfilter sesuatu dari koleksi "sumber" sebagai operasi pertama kami. Dan ini umumnya merupakan praktik yang baik karena menghapus dokumen apa pun yang tidak memenuhi persyaratan yang disyaratkan dari kondisi lebih lanjut. Sama seperti apa yang terjadi dalam contoh "pipa baris perintah" kami, di mana kami mengambil "input" lalu "pipa" ke grep untuk "menghapus" atau "menyaring".

Jalur Penting

Di mana hal berikutnya yang Anda lakukan di sini adalah "bergabung" melalui $lookup . Hasilnya adalah "array" item dari "from" argumen koleksi dicocokkan dengan bidang yang disediakan untuk keluaran di "as" "jalur bidang" sebagai "array".

Penamaan yang dipilih di sini penting, karena sekarang "dokumen" dari koleksi sumber menganggap semua item dari "gabung" sekarang ada di jalur yang diberikan. Untuk mempermudah ini, saya menggunakan nama "koleksi" yang sama dengan "bergabung" untuk "jalur" baru.

Jadi mulai dari "join" pertama hasilnya adalah "tb2" dan itu akan menampung semua hasil dari koleksi itu. Ada juga hal penting yang perlu diperhatikan dengan urutan berikut $unwind lalu $match , tentang bagaimana sebenarnya MongoDB memproses kueri.

Urutan tertentu "benar-benar" penting

Karena "sepertinya" ada "tiga" tahapan saluran, menjadi $lookup lalu $unwind lalu $match . Tetapi pada kenyataannya, MongoDB benar-benar melakukan sesuatu yang lain, yang ditunjukkan dalam output { "explain": true } ditambahkan ke .aggregate() perintah:

    {
        "$lookup" : {
            "from" : "tb2",
            "as" : "tb2",
            "localField" : "id",
            "foreignField" : "profileId",
            "unwinding" : {
                "preserveNullAndEmptyArrays" : false
            },
            "matching" : {
                "profile_type" : {
                    "$eq" : "agent"
                }
            }
        }
    }, 
    {
        "$lookup" : {
            "from" : "tb3",
            "as" : "tb3",
            "localField" : "tb2.id",
            "foreignField" : "id",
            "unwinding" : {
                "preserveNullAndEmptyArrays" : false
            },
            "matching" : {
                "status" : {
                    "$eq" : 0.0
                }
            }
        }
    }, 

Jadi selain dari poin pertama "urutan" penerapan di mana Anda harus meletakkan $match pernyataan di mana mereka dibutuhkan dan melakukan yang "paling baik", ini sebenarnya menjadi "sangat penting" dengan konsep "bergabung". Hal yang perlu diperhatikan di sini adalah urutan $lookup lalu $unwind lalu $match , sebenarnya diproses oleh MongoDB hanya sebagai $lookup tahap, dengan operasi lain "digabungkan" ke dalam satu tahap saluran untuk masing-masing.

Ini adalah perbedaan penting untuk cara lain "memfilter" hasil yang diperoleh dengan $lookup . Karena dalam kasus ini, kondisi "query" yang sebenarnya pada "join" dari $match dilakukan pada koleksi untuk bergabung "sebelum" hasilnya dikembalikan ke induk.

Ini dikombinasikan dengan $unwind ( yang diterjemahkan menjadi unwinding ) seperti yang ditunjukkan di atas adalah bagaimana MongoDB benar-benar menangani kemungkinan bahwa "bergabung" dapat mengakibatkan menghasilkan larik konten dalam dokumen sumber yang menyebabkannya melebihi batas BSON 16MB. Ini hanya akan terjadi dalam kasus di mana hasil yang digabungkan sangat besar, tetapi keuntungan yang sama adalah di mana "filter" benar-benar diterapkan, berada di kumpulan target "sebelum" hasil dikembalikan.

Ini adalah jenis penanganan yang paling "berkorelasi" dengan perilaku yang sama dengan SQL JOIN. Oleh karena itu, ini juga merupakan cara paling efektif untuk mendapatkan hasil dari $lookup di mana ada kondisi lain untuk diterapkan pada GABUNG selain dari nilai kunci "lokal" dari nilai kunci "asing".

Perhatikan juga bahwa perubahan perilaku lainnya adalah dari apa yang pada dasarnya adalah LEFT JOIN yang dilakukan oleh $lookup di mana dokumen "sumber" akan selalu disimpan terlepas dari keberadaan dokumen yang cocok dalam koleksi "target". Alih-alih $unwind menambahkan ini dengan "membuang" hasil apa pun dari "sumber" yang tidak memiliki apa pun yang cocok dari "target" dengan ketentuan tambahan di $match .

Bahkan mereka bahkan dibuang sebelumnya karena tersirat preserveNullAndEmptyArrays: false yang disertakan dan akan membuang apa pun di mana kunci "lokal" dan "asing" bahkan tidak cocok di antara dua koleksi. Ini adalah hal yang baik untuk jenis kueri khusus ini karena "gabung" dimaksudkan untuk "sama" pada nilai-nilai tersebut.

Simpulkan

Seperti disebutkan sebelumnya, MongoDB umumnya memperlakukan "hubungan" dengan sangat berbeda dengan cara Anda menggunakan "Database Relasional" atau RDBMS. Konsep umum "hubungan" sebenarnya adalah "menyematkan" data, baik sebagai properti tunggal atau sebagai larik.

Anda mungkin benar-benar menginginkan keluaran seperti itu, yang juga merupakan bagian dari alasan mengapa tanpa $unwind urutkan di sini output dari $lookup sebenarnya adalah "array". Namun menggunakan $unwind dalam konteks ini sebenarnya adalah hal yang paling efektif untuk dilakukan, sekaligus memberikan jaminan bahwa data yang "bergabung" tidak benar-benar menyebabkan batas BSON tersebut di atas terlampaui sebagai akibat dari "bergabung" tersebut.

Jika Anda benar-benar menginginkan array keluaran, maka hal terbaik untuk dilakukan di sini adalah menggunakan $group tahap pipa, dan mungkin sebagai beberapa tahap untuk "menormalkan" dan "membatalkan hasil" dari $unwind

  { "$group": {
    "_id": "$_id",
    "tb1_field": { "$first": "$tb1_field" },
    "tb1_another": { "$first": "$tb1_another" },
    "tb3": { "$push": "$tb3" }    
  }}

Di mana Anda sebenarnya untuk kasus ini mencantumkan semua bidang yang Anda perlukan dari "tb1" dengan nama properti mereka menggunakan $first untuk hanya menyimpan kejadian "pertama" ( pada dasarnya diulang dengan hasil "tb2" dan "tb3" unwound ) lalu $push "detail" dari "tb3" ke dalam "array" untuk merepresentasikan relasi ke "tb1" .

Tetapi bentuk umum dari pipa agregasi seperti yang diberikan adalah representasi yang tepat tentang bagaimana hasil akan diperoleh dari SQL asli, yang merupakan keluaran "denormalisasi" sebagai hasil dari "gabungan". Apakah Anda ingin "menormalkan" hasil lagi setelah ini terserah Anda.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Bagaimana cara melindungi bidang kata sandi di Mongoose/MongoDB sehingga tidak akan kembali dalam kueri ketika saya mengisi koleksi?

  2. Tidak dapat memulai MongoDB sebagai layanan

  3. Kata sandi MongoDB dengan @ di dalamnya

  4. Kueri dengan format tanggal string di mongodb

  5. Instal/Pengaturan Mongo di Pohon Kacang Elastis