MongoDB MapReduce, kembali hanya jika hitungan › 1

Saya memiliki data di MongoDB. Struktur suatu objek adalah seperti ini:

{
    "_id" : ObjectId("5395177980a6b1ccf916312c"),
    "institutionId" : "831",
    "currentObject" : {
          "systemIdentifiers" : [
            {
                "value" : "24387",
                "system" : "ABC"
            }]
      }
}

Saya harus mengetahui berapa banyak objek yang memiliki institutionId dan systemIdentifiers[0].value yang sama dan hanya ingin mengembalikan objek yang diduplikasi dengan cara itu. Untuk melakukan itu saya mengelompokkannya berdasarkan ID ini dan menghitung kejadiannya.

Objek (sepasang ID) harus dikembalikan ketika count lebih besar dari 1.

Ini adalah potongan kode yang dikelompokkan dengan menggunakan MapReduce.

var map = function() {
    var key = this.institutionId;
    var val = this.currentObject.systemIdentifiers[0].value;
    emit({"institutionId":key,"workId":val}, {count:1});     
};
var reduce = function(key, values) {
    var count = 0;
    values.forEach(function(v) {
        count += v['count'];
    });
    return {count: count};
}
db.name.mapReduce(map, reduce, {out: "grouped"})
db.grouped.find()

Untuk mendapatkan hanya mereka yang memiliki hitungan lebih besar dari 1, saya lakukan

db.grouped.aggregate([{$match:{"value.count":{$gt: 1}}}])

Contoh hasilnya adalah sebagai berikut

{
    "_id" : {
        "institutionId" : "1004",
        "workId" : "591426"
    },
    "value" : {
        "count" : 2
    }
}

Tapi saya penasaran apakah mungkin melakukannya hanya dengan melakukan MapReduce sebagai satu pernyataan. Seperti menambahkan finalizer atau lebih.


person Szymon Roziewski    schedule 01.12.2016    source sumber


Jawaban (2)


Pendekatan yang jauh lebih baik, sederhana dan efisien adalah dengan menggunakan kerangka agregasi di mana Anda dapat menggunakan operator seperti $arrayElemAt untuk mengembalikan subdokumen pertama dari array dan kemudian menggunakan $group pipeline untuk menggabungkan jumlah. Anda kemudian dapat menempatkan $match saluran untuk memfilter hasil Anda berdasarkan kriteria yang diberikan.

Contoh berikut menunjukkan pendekatan yang lebih cepat ini:

db.name.aggregate([
    {
        "$project": {
            "key": "$institutionId",
            "val": {
                "$arrayElemAt": ["$currentObject.systemIdentifiers", 0]
            }
        }
    },
    {
        "$group": {
            "_id": {
                "institutionId": "$key",
                "workId": "$val.value"
            },
            "count": { "$sum": 1 }
        }
    },
    { "$match": { "count": { "$gt": 1 } } }
])
person chridam    schedule 06.12.2016

Jika ada satu dokumen yang memiliki kunci maka dokumen tersebut tidak akan pernah masuk ke dalam pengurangan, dianggap sudah dikurangi, itulah perilaku pengurangan peta MongoDB:

MongoDB tidak akan memanggil fungsi pengurangan untuk a kunci yang hanya memiliki satu nilai.

Menggunakan finalzie juga tidak banyak membantu, yaitu jika dalam fungsi finalisasi Anda melakukan if count > 1 then return reducedVal else None, maka hasilnya akan Tidak Ada (bukan 1).

Saya khawatir dengan menggunakan (satu) pengurangan peta, dokumen yang memiliki hitungan 1 akan selalu muncul di hasil, karena dikeluarkan dari peta.

Anda dapat menggunakan 2 operasi pengurangan peta dalam satu rantai, di peta kedua Anda tidak mengeluarkan dokumen yang memiliki jumlah ‹ 2. Namun menurut mereka ini tidak lebih baik daripada kueri tambahan seperti pada contoh Anda.

person sergiuz    schedule 01.12.2016