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

Menautkan &Membuat Gabungan MongoDB Menggunakan SQL:Bagian 2

BERGABUNG adalah salah satu fitur utama yang berbeda antara database SQL dan NoSQL. Dalam database SQL, kita dapat melakukan JOIN antara dua tabel dalam database yang sama atau berbeda. Namun, ini tidak berlaku untuk MongoDB karena memungkinkan operasi GABUNG antara dua koleksi dalam database yang sama.

Cara data disajikan di MongoDB membuatnya hampir mustahil untuk menghubungkannya dari satu koleksi ke koleksi lainnya kecuali saat menggunakan fungsi kueri skrip dasar. MongoDB mendenormalisasi data dengan menyimpan item terkait dalam dokumen terpisah atau menghubungkan data dalam beberapa dokumen terpisah lainnya.

Seseorang dapat menghubungkan data ini dengan menggunakan referensi manual seperti bidang _id dari satu dokumen yang disimpan di dokumen lain sebagai referensi. Namun demikian, seseorang perlu membuat beberapa kueri untuk mengambil beberapa data yang diperlukan, sehingga prosesnya sedikit membosankan.

Oleh karena itu kami memutuskan untuk menggunakan konsep JOIN yang memfasilitasi hubungan data. Operasi GABUNG di MongoDB dicapai melalui penggunaan operator $lookup, yang diperkenalkan di versi 3.2.

$operator pencarian

Gagasan utama di balik konsep JOIN adalah untuk mendapatkan korelasi antara data dalam satu koleksi dengan koleksi lainnya. Sintaks dasar dari operator $lookup adalah:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

Mengenai pengetahuan SQL, kita selalu tahu bahwa hasil dari operasi JOIN adalah baris terpisah yang menghubungkan semua bidang dari tabel lokal dan asing. Untuk MongoDB, ini adalah kasus yang berbeda di mana dokumen hasil ditambahkan sebagai larik dokumen koleksi lokal. Misalnya, mari kita punya dua koleksi; 'siswa' dan 'unit'

siswa

{"_id" : 1,"name" : "James Washington","age" : 15.0,"grade" : "A","score" : 10.5}
{"_id" : 2,"name" : "Clinton Ariango","age" : 14.0,"grade" : "B","score" : 7.5}
{"_id" : 3,"name" : "Mary Muthoni","age" : 16.0,"grade" : "A","score" : 11.5}

Satuan

{"_id" : 1,"Maths" : "A","English" : "A","Science" : "A","History" : "B"}
{"_id" : 2,"Maths" : "B","English" : "B","Science" : "A","History" : "B"}
{"_id" : 3,"Maths" : "A","English" : "A","Science" : "A","History" : "A"}

Kita dapat mengambil unit siswa dengan nilai masing-masing menggunakan operator $lookup dengan pendekatan GABUNG .i.e

db.getCollection('students').aggregate([{
$lookup:
    {
        from: "units",
        localField: "_id",
        foreignField : "_id",
        as: "studentUnits"
    }
}])

Yang akan memberi kita hasil di bawah ini:

{"_id" : 1,"name" : "James Washington","age" : 15,"grade" : "A","score" : 10.5,
    "studentUnits" : [{"_id" : 1,"Maths" : "A","English" : "A","Science" : "A","History" : "B"}]}
{"_id" : 2,"name" : "Clinton Ariango","age" : 14,"grade" : "B","score" : 7.5,
    "studentUnits" : [{"_id" : 2,"Maths" : "B","English" : "B","Science" : "A","History" : "B"}]}
{"_id" : 3,"name" : "Mary Muthoni","age" : 16,"grade" : "A","score" : 11.5,
    "studentUnits" : [{"_id" : 3,"Maths" : "A","English" : "A","Science" : "A","History" : "A"}]}

Seperti yang disebutkan sebelumnya, jika kita melakukan JOIN menggunakan konsep SQL, kita akan dikembalikan dengan dokumen terpisah di platform Studio3T .i.e

SELECT *
  FROM students
    INNER JOIN units
      ON students._id = units._id

Setara dengan

db.getCollection("students").aggregate(
    [
        { 
            "$project" : {
                "_id" : NumberInt(0), 
                "students" : "$$ROOT"
            }
        }, 
        { 
            "$lookup" : {
                "localField" : "students._id", 
                "from" : "units", 
                "foreignField" : "_id", 
                "as" : "units"
            }
        }, 
        { 
            "$unwind" : {
                "path" : "$units", 
                "preserveNullAndEmptyArrays" : false
            }
        }
    ]
);

Kueri SQL di atas akan mengembalikan hasil di bawah ini:

{ "students" : {"_id" : NumberInt(1),"name" : "James Washington","age" : 15.0,"grade" : "A","score" : 10.5}, 
    "units" : {"_id" : NumberInt(1),"Maths" : "A","English" : "A","Science" : "A","History" : "B"}}
{ "students" : {"_id" : NumberInt(2), "name" : "Clinton Ariango","age" : 14.0,"grade" : "B","score" : 7.5 }, 
    "units" : {"_id" : NumberInt(2),"Maths" : "B","English" : "B","Science" : "A","History" : "B"}}
{ "students" : {"_id" : NumberInt(3),"name" : "Mary Muthoni","age" : 16.0,"grade" : "A","score" : 11.5},
"units" : {"_id" : NumberInt(3),"Maths" : "A","English" : "A","Science" : "A","History" : "A"}}

Durasi kinerja jelas akan tergantung pada struktur kueri Anda. Misalnya, jika Anda memiliki banyak dokumen dalam satu koleksi di atas yang lain, Anda harus melakukan agregasi dari koleksi dengan dokumen yang lebih sedikit dan kemudian mencari yang memiliki lebih banyak dokumen. Dengan cara ini, pencarian untuk bidang yang dipilih dari koleksi dokumen yang lebih sedikit cukup optimal dan membutuhkan waktu lebih sedikit daripada melakukan pencarian ganda untuk bidang yang dipilih dalam koleksi dengan lebih banyak dokumen. Oleh karena itu, disarankan untuk mendahulukan koleksi yang lebih kecil.

Untuk database relasional, urutan database tidak menjadi masalah karena sebagian besar interpreter SQL memiliki pengoptimal, yang memiliki akses ke informasi tambahan untuk memutuskan mana yang harus lebih dulu.

Dalam kasus MongoDB, kita perlu menggunakan indeks untuk memfasilitasi operasi JOIN. Kita semua tahu bahwa semua dokumen MongoDB memiliki kunci _id yang untuk DBM relasional dapat dianggap sebagai kunci utama. Indeks memberikan peluang yang lebih baik untuk mengurangi jumlah data yang perlu diakses selain mendukung operasi saat digunakan dalam kunci asing $lookup.

Dalam pipa agregasi, untuk menggunakan indeks, kita harus memastikan $match dilakukan tahap pertama untuk menyaring dokumen yang tidak sesuai dengan kriteria. Misalnya jika kita ingin mengambil hasil untuk siswa dengan nilai bidang _id sama dengan 1:

select * 
from students 
  INNER JOIN units 
    ON students._id = units._id 
      WHERE students._id = 1;

Kode MongoDB setara yang akan Anda dapatkan dalam hal ini adalah:

db.getCollection("students").aggregate(
[{"$project" : { "_id" : NumberInt(0), "students" : "$$ROOT" }}, 
     {  "$lookup" : {"localField" : "students._id", "from" : "units",  "foreignField" : "_id",  "as" : "units"} }, 
     { "$unwind" : { "path" : "$units","preserveNullAndEmptyArrays" : false } }, 
      { "$match" : {"students._id" : NumberLong(1) }}
    ]);

Hasil yang dikembalikan untuk kueri di atas adalah:

{"_id" : 1,"name" : "James Washington","age" : 15,"grade" : "A","score" : 10.5,
    "studentUnits" : [{"_id" : 1,"Maths" : "A","English" : "A","Science" : "A","History" : "B"}]}

Ketika kita tidak menggunakan tahap $match atau lebih tepatnya tidak pada tahap pertama, jika kita memeriksa dengan fungsi menjelaskan, kita akan mendapatkan tahap COLLSCAN juga disertakan. Melakukan COLLSCAN untuk sekumpulan besar dokumen umumnya akan memakan banyak waktu. Dengan demikian kami memutuskan untuk menggunakan bidang indeks yang dalam fungsi jelaskan hanya melibatkan tahap IXSCAN. Yang terakhir memiliki keuntungan karena kami memeriksa indeks dalam dokumen dan tidak memindai semua dokumen; tidak akan lama untuk mengembalikan hasilnya. Anda mungkin memiliki struktur data yang berbeda seperti:

{    "_id" : NumberInt(1), 
    "grades" : {"Maths" : "A", "English" : "A",  "Science" : "A", "History" : "B"
    }
}

Kami mungkin ingin mengembalikan nilai sebagai entitas yang berbeda dalam larik daripada seluruh bidang nilai yang disematkan.

Setelah menulis query SQL di atas, kita perlu memodifikasi kode MongoDB yang dihasilkan. Untuk melakukannya, klik ikon salin di sebelah kanan seperti di bawah ini untuk menyalin kode agregasi:

Selanjutnya buka tab agregasi dan pada panel yang disajikan, ada ikon tempel, klik untuk menempelkan kode.

Klik baris $match dan kemudian panah atas berwarna hijau untuk memindahkan stage ke atas sebagai stage pertama. Namun, Anda harus membuat indeks di koleksi Anda terlebih dahulu seperti:

db.students.createIndex(
   { _id: 1 },
   { name: studentId }
)

Anda akan mendapatkan contoh kode di bawah ini:

db.getCollection("students").aggregate(
    [{ "$match" : {"_id" : 1.0}},
  { "$project" : {"_id" : NumberInt(0),"students" : "$$ROOT"}}, 
      { "$lookup" : {"localField" : "students._id","from" : "units","foreignField" : "_id","as" : "units"}}, 
      { "$unwind" : {"path" : "$units", "preserveNullAndEmptyArrays" : false}}
    ]
Beberapa Sembilan Menjadi DBA MongoDB - Membawa MongoDB ke ProduksiPelajari tentang apa yang perlu Anda ketahui untuk menerapkan, memantau, mengelola, dan menskalakan MongoDBUnduh secara Gratis

Dengan kode ini kita akan mendapatkan hasil di bawah ini:

{ "students" : {"_id" : NumberInt(1), "name" : "James Washington","age" : 15.0,"grade" : "A", "score" : 10.5}, 
    "units" : {"_id" : NumberInt(1), "grades" : {"Maths" : "A", "English" : "A", "Science" : "A",  "History" : "B"}}}

Tetapi yang kita butuhkan hanyalah memiliki nilai sebagai entitas dokumen terpisah dalam dokumen yang dikembalikan dan bukan seperti contoh di atas. Kami kemudian akan menambahkan tahap $addfields maka kode seperti di bawah ini.

db.getCollection("students").aggregate(
    [{ "$match" : {"_id" : 1.0}},
  { "$project" : {"_id" : NumberInt(0),"students" : "$$ROOT"}}, 
      { "$lookup" : {"localField" : "students._id","from" : "units","foreignField" : "_id","as" : "units"}}, 
      { "$unwind" : {"path" : "$units", "preserveNullAndEmptyArrays" : false}},
      { "$addFields" : {"units" : "$units.grades"} }]

Dokumen yang dihasilkan akan menjadi:

{
"students" : {"_id" : NumberInt(1), "name" : "James Washington", "grade" : "A","score" : 10.5}, 
     "units" : {"Maths" : "A", "English" : "A",  "Science" : "A", "History" : "B"}
}

Data yang dikembalikan cukup rapi, karena kami telah menghilangkan dokumen yang disematkan dari koleksi unit sebagai bidang terpisah.

Dalam tutorial berikutnya, kita akan melihat kueri dengan beberapa gabungan.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. 'upsert' dalam dokumen yang disematkan

  2. Bagaimana cara menanyakan objek bersarang?

  3. apakah ada panggilan balik kesalahan koneksi luwak?

  4. Menggunakan UUID alih-alih ObjectID di MongoDB

  5. Cara memilih subdokumen dengan MongoDB