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

Memperbarui array bersarang di dalam array mongodb

MongoDB 3.6 dan yang lebih baru

Dengan MongoDB 3.6 dan di atasnya, hadir fitur baru yang memungkinkan Anda memperbarui array bersarang dengan menggunakan $\[<identifier>\] yang difilter posisi sintaks untuk mencocokkan elemen tertentu dan menerapkan kondisi yang berbeda melalui arrayFilters dalam pernyataan pembaruan:

const { oid, pid } = req.params;
const { name, oName, description, type } = req.body; 

collection.update(
    {
        "_id": 1,
        "operations": {
            "$elemMatch": {
                oid, "parameters.pid": pid
            }
        }
    },
    { "$set": { 
        "operations.$[outer].parameters.$[inner].name": name,
        "operations.$[outer].parameters.$[inner].description": description,
        "operations.$[outer].parameters.$[inner].oName": oName,
        "operations.$[outer].parameters.$[inner].type": type 
    } },
    { "arrayFilters": [
        { "outer.oid": oid },
        { "inner.pid": pid }
    ] }, (err, result) => {
    if (err) {
        console.log('Error updating service: ' + err);
        res.send({'error':'An error has occurred'});
    } else {
        // console.log('' + result + ' document(s) updated');
        res.send(result);
    }
});

Untuk MongoDB 3.4 dan yang lebih lama:

Seperti yang disebutkan @wdberkeley dalam komentarnya:

MongoDB tidak mendukung pencocokan ke lebih dari satu tingkat larik. Pertimbangkan untuk mengubah model dokumen Anda sehingga setiap dokumen mewakili suatu operasi, dengan informasi umum untuk sekumpulan operasi yang diduplikasi dalam dokumen operasi.

Saya setuju dengan hal di atas dan akan merekomendasikan mendesain ulang skema Anda karena mesin MongoDB tidak mendukung banyak operator posisi ( Lihat Beberapa penggunaan $ posisional operator untuk memperbarui array bersarang )

Namun, jika Anda mengetahui indeks dari array operasi yang memiliki objek parameter yang akan diupdate sebelumnya maka query update akan menjadi:

db.collection.update(
    {
        "_id" : "04", 
        "operations.parameters.pid": "011"
    }, 
    {
        "$set": { 
            "operations.0.parameters.$.name": "foo",
            "operations.0.parameters.$.description": "bar", 
            "operations.0.parameters.$.type": "foo" 
        }
    }
)

EDIT:

Jika Anda ingin membuat $set kondisi dengan cepat yaitu sesuatu yang akan membantu Anda mendapatkan indeks untuk objek dan kemudian memodifikasinya, lalu pertimbangkan untuk menggunakan MapReduce .

Saat ini tampaknya tidak mungkin menggunakan kerangka kerja agregasi. Ada masalah JIRA terbuka yang belum terselesaikan terkait dengannya. Namun, solusi dapat dilakukan dengan MapReduce . Ide dasar MapReduce adalah bahwa ia menggunakan JavaScript sebagai bahasa kuerinya tetapi ini cenderung lebih lambat daripada kerangka kerja agregasi dan tidak boleh digunakan untuk analisis data waktu nyata.

Dalam operasi MapReduce Anda, Anda perlu menentukan beberapa langkah yaitu langkah pemetaan (yang memetakan operasi ke dalam setiap dokumen dalam koleksi, dan operasi tidak dapat melakukan apa pun atau memancarkan beberapa objek dengan kunci dan nilai yang diproyeksikan) dan langkah pengurangan ( yang mengambil daftar nilai yang dipancarkan dan menguranginya menjadi satu elemen).

Untuk langkah peta, idealnya Anda ingin mendapatkan untuk setiap dokumen dalam koleksi, indeks untuk setiap operations bidang array dan kunci lain yang berisi $set kunci.

Langkah pengurangan Anda akan menjadi fungsi (yang tidak melakukan apa-apa) hanya didefinisikan sebagai var reduce = function() {};

Langkah terakhir dalam operasi MapReduce Anda kemudian akan membuat operasi pengumpulan terpisah yang berisi objek larik operasi yang dipancarkan bersama dengan bidang dengan $set kondisi. Koleksi ini dapat diperbarui secara berkala saat Anda menjalankan operasi MapReduce pada koleksi asli. Secara keseluruhan, metode MapReduce ini akan terlihat seperti:

var map = function(){
    for(var i = 0; i < this.operations.length; i++){
        emit( 
            {
                "_id": this._id, 
                "index": i 
            }, 
            {
                "index": i, 
                "operations": this.operations[i],            
                "update": {
                    "name": "operations." + i.toString() + ".parameters.$.name",
                    "description": "operations." + i.toString() + ".parameters.$.description",
                    "type": "operations." + i.toString() + ".parameters.$.type"
                }                    
            }
        );
    }
};

var reduce = function(){};

db.collection.mapReduce(
    map,
    reduce,
    {
        "out": {
            "replace": "operations"
        }
    }
);

Mengkueri koleksi keluaran operations dari operasi MapReduce biasanya akan memberikan Anda hasil:

db.operations.findOne()

Keluaran :

{
    "_id" : {
        "_id" : "03",
        "index" : 0
    },
    "value" : {
        "index" : 0,
        "operations" : {
            "_id" : "96",
            "oName" : "test op 52222222222",
            "sid" : "04",
            "name" : "test op 52222222222",
            "oid" : "99",
            "description" : "testing",
            "returntype" : "test",
            "parameters" : [ 
                {
                    "oName" : "Param1",
                    "name" : "foo",
                    "pid" : "011",
                    "type" : "foo",
                    "description" : "bar",
                    "value" : ""
                }, 
                {
                    "oName" : "Param2",
                    "name" : "Param2",
                    "pid" : "012",
                    "type" : "58222",
                    "description" : "testing",
                    "value" : ""
                }
            ]
        },
        "update" : {
            "name" : "operations.0.parameters.$.name",
            "description" : "operations.0.parameters.$.description",
            "type" : "operations.0.parameters.$.type"
        }
    }
}

Anda kemudian dapat menggunakan kursor dari db.operations.find() metode untuk mengulangi dan memperbarui koleksi Anda yang sesuai:

var oid = req.params.operations;
var pid = req.params.parameters;
var cur = db.operations.find({"_id._id": oid, "value.operations.parameters.pid": pid });

// Iterate through results and update using the update query object set dynamically by using the array-index syntax.
while (cur.hasNext()) {
    var doc = cur.next();
    var update = { "$set": {} };
    // set the update query object
    update["$set"][doc.value.update.name] = req.body.name;
    update["$set"][doc.value.update.description] = req.body.description;
    update["$set"][doc.value.update.type] = req.body.type;

    db.collection.update(
        {
            "_id" : oid, 
            "operations.parameters.pid": pid
        }, 
        update 
    );
};


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Apakah Luwak menyediakan akses ke nilai properti sebelumnya di pra('simpan')?

  2. Panggil fungsi tersimpan di mongodb

  3. Penyortiran MongoDB

  4. mongodb temukan dengan membandingkan nilai bidang

  5. Bagaimana cara mengatur kunci utama di MongoDB?