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

Menemukan dua dokumen di MongoDB yang berbagi nilai kunci

Sementara saya berdiri dengan komentar bahwa saya tidak berpikir cara Anda mengutarakan pertanyaan Anda sebenarnya terkait dengan masalah spesifik yang Anda miliki, saya akan menjelaskan cara SQL idiomatik dalam jenis solusi MongoDB. Saya yakin bahwa solusi Anda yang sebenarnya akan berbeda tetapi Anda tidak memberikan masalah itu kepada kami, tetapi hanya SQL.

Jadi pertimbangkan dokumen berikut sebagai kumpulan sampel, hapus bidang _id dalam daftar ini untuk kejelasan:

{ "name" : "a", "type" : "b" }
{ "name" : "a", "type" : "c" }
{ "name" : "b", "type" : "c" }
{ "name" : "b", "type" : "a" }
{ "name" : "a", "type" : "b" }
{ "name" : "b", "type" : "c" }
{ "name" : "f", "type" : "e" }
{ "name" : "z", "type" : "z" }
{ "name" : "z", "type" : "z" }

Jika kita menjalankan SQL yang disajikan pada data yang sama, kita akan mendapatkan hasil ini:

a|b
a|c
a|c
b|c
b|a
b|a
a|b
b|c

Kita dapat melihat bahwa 2 dokumen tidak cocok, dan kemudian menyusun logika operasi SQL. Jadi cara lain untuk mengatakannya adalah "Dokumen mana yang diberi kunci "nama" lakukan memiliki lebih dari satu kemungkinan nilai dalam kunci "type".

Mengingat bahwa, dengan menggunakan pendekatan mongo, kita dapat melakukan kueri untuk item yang tidak cocok dengan kondisi yang diberikan. Jadi efektifnya kebalikan dari hasil:

db.sample.aggregate([

    // Store unique documents grouped by the "name"
    {$group: { 
        _id: "$name",
        comp: {
            $addToSet: { 
                name:"$name",
                type: "$type" 
            }
        } 
    }},

    // Unwind the "set" results
    {$unwind: "$comp"},

    // Push the results back to get the unique count
    // *note* you could not have done this with alongside $addtoSet
    {$group: {
        _id: "$_id",
        comp: {
            $push: { 
                name: "$comp.name",
                type: "$comp.type" 
            }
        },
        count: {$sum: 1} 
    }},

    // Match only what was counted once
    {$match: {count: 1}},

    // Unwind the array
    {$unwind: "$comp"},

    // Clean up to "name" and "type" only
    {$project: { _id: 0, name: "$comp.name", type: "$comp.type"}}

])

Operasi ini akan memberikan hasil:

{ "name" : "f", "type" : "e" }
{ "name" : "z", "type" : "z" }

Sekarang untuk mendapatkan hasil yang sama dengan kueri SQL, kami akan mengambil hasil tersebut dan menyalurkannya ke kueri lain:

db.sample.find({$nor: [{ name: "f", type: "e"},{ name: "z", type: "z"}] })

Yang muncul sebagai hasil pencocokan akhir:

{ "name" : "a", "type" : "b" }
{ "name" : "a", "type" : "c" }
{ "name" : "b", "type" : "c" }
{ "name" : "b", "type" : "a" }
{ "name" : "a", "type" : "b" }
{ "name" : "b", "type" : "c" }

Jadi ini akan berhasil, namun satu hal yang mungkin membuat ini tidak praktis adalah jumlah dokumen yang dibandingkan sangat besar, kami mencapai batas kerja untuk memadatkan hasil tersebut ke dalam array.

Itu juga sedikit menderita karena penggunaan negatif dalam operasi pencarian terakhir yang akan memaksa pemindaian koleksi. Tetapi dalam semua keadilan, hal yang sama dapat dikatakan tentang kueri SQL yang menggunakan negatif . yang sama premis.

Sunting

Tentu saja yang tidak saya sebutkan adalah jika rangkaian hasil sebaliknya dan Anda cocok lebih menghasilkan item yang dikecualikan dari agregat, lalu hanya membalikkan logika untuk mendapatkan kunci yang Anda inginkan. Cukup ubah $match sebagai berikut:

{$match: {$gt: 1}}

Dan itu akan menjadi hasilnya, mungkin bukan dokumen yang sebenarnya tetapi itu adalah hasilnya. Jadi, Anda tidak perlu kueri lain untuk mencocokkan kasus negatif.

Dan, pada akhirnya ini adalah kesalahan saya karena saya terlalu fokus pada terjemahan idiomatik sehingga saya tidak membaca baris terakhir dalam pertanyaan Anda, di mana melakukan katakan bahwa Anda sedang mencari satu dokumen.

Tentu saja, saat ini jika ukuran hasil itu lebih besar dari 16MB maka Anda macet. Setidaknya sampai 2.6 rilis, di mana hasil operasi agregasi adalah kursor , sehingga Anda dapat mengulanginya seperti .find() .

Juga diperkenalkan di 2.6 adalah $size operator yang digunakan untuk mencari ukuran array dalam dokumen. Jadi ini akan membantu untuk menghapus $unwind second kedua dan $group yang digunakan untuk mendapatkan panjang himpunan. Ini mengubah kueri ke bentuk yang lebih cepat:

db.sample.aggregate([
    {$group: { 
        _id: "$name",
        comp: {
            $addToSet: { 
                name:"$name",
                type: "$type"
            }
        } 
    }},
    {$project: { 
        comp: 1,
        count: {$size: "$comp"} 
    }},
    {$match: {count: {$gt: 1}}},
    {$unwind: "$comp"},
    {$project: { _id: 0, name: "$comp.name", type: "$comp.type"}}
])

Dan MongoDB 2.6.0-rc0 saat ini tersedia jika Anda melakukan ini hanya untuk penggunaan pribadi, atau pengembangan/pengujian.

Pesan moral dalam cerita. Ya, Anda bisa lakukan, Tapi apakah kamu benarkah ingin atau membutuhkan untuk melakukannya dengan cara itu? Maka mungkin tidak, dan jika Anda mengajukan pertanyaan berbeda tentang kasus bisnis tertentu, Anda mungkin mendapatkan jawaban yang berbeda. Tapi sekali lagi ini mungkin tepat untuk apa yang Anda inginkan.

Catatan

Patut disebutkan bahwa ketika Anda melihat hasil dari SQL, itu akan salah duplikat beberapa item karena opsi jenis lain yang tersedia jika Anda tidak menggunakan DISTINCT untuk nilai-nilai itu atau pada dasarnya pengelompokan lain. Tapi itulah hasil yang dihasilkan oleh proses ini menggunakan MongoDB.

Untuk Alexander

Ini adalah output dari agregat di shell dari versi 2.4.x saat ini:

{
    "result" : [
            {
                    "name" : "f",
                    "type" : "e"
            },
            {
                    "name" : "z",
                    "type" : "z"
            }
    ],
    "ok" : 1
}

Jadi lakukan ini untuk mendapatkan var untuk diteruskan sebagai argumen ke kondisi $nor di temuan kedua, seperti ini:

var cond = db.sample.aggregate([ .....

db.sample.find({$nor: cond.result })

Dan Anda harus mendapatkan hasil yang sama. Jika tidak, hubungi pengemudi Anda.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Bagaimana cara menghapus dokumen di MongoDB?

  2. Adakah alasan terperinci dan spesifik untuk Mengapa MongoDB jauh lebih cepat daripada SQL DB?

  3. Struktur hierarki Firestore dan subkoleksi

  4. Bagaimana cara menggunakan $lookup sebagai INNER JOIN di Agregasi MongoDB?

  5. Hapus _Id dari respons Agregat luwak