sql >> Databáze >  >> NoSQL >> MongoDB

Aktualizace vnořeného pole uvnitř pole mongodb

MongoDB 3.6 a novější

S MongoDB 3.6 a vyšší přichází nová funkce, která vám umožňuje aktualizovat vnořená pole pomocí pozičně filtrovaného $\[<identifier>\] syntaxi, aby odpovídaly konkrétním prvkům a aplikovaly různé podmínky prostřednictvím arrayFilters v prohlášení o aktualizaci:

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);
    }
});

Pro MongoDB 3.4 a starší:

Jak uvedl @wdberkeley ve svém komentáři:

MongoDB nepodporuje párování do více než jedné úrovně pole. Zvažte změnu modelu dokumentu tak, aby každý dokument představoval operaci s informacemi společnými sadě operací duplikovaných v dokumentech operací.

Souhlasím s výše uvedeným a doporučil bych přepracovat vaše schéma, protože motor MongoDB nepodporuje více pozičních operátorů (viz Vícenásobné použití pozičního $ operátor pro aktualizaci vnořených polí )

Pokud však znáte index pole operací, které má objekt s parametry, který se má aktualizovat, bude aktualizační dotaz znít:

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" 
        }
    }
)

UPRAVIT:

Pokud byste chtěli vytvořit $set podmínky za běhu, tj. něco, co by vám pomohlo získat indexy pro objekty a následně je upravit, poté zvažte použití MapReduce .

V současné době se zdá, že to není možné pomocí agregačního rámce. Existuje nevyřešený otevřený problém JIRA s tím spojené. Řešení je však možné pomocí MapReduce . Základní myšlenkou MapReduce je, že používá JavaScript jako svůj dotazovací jazyk, ale ten bývá poměrně pomalejší než agregační rámec a neměl by být používán pro analýzu dat v reálném čase.

Ve vaší operaci MapReduce musíte definovat několik kroků, tj. krok mapování (který mapuje operaci do každého dokumentu v kolekci a operace nemůže buď nic dělat, nebo může vysílat nějaký objekt s klíči a projektovanými hodnotami) a krok zmenšení ( který převezme seznam emitovaných hodnot a zredukuje jej na jediný prvek).

Pro krok mapy byste v ideálním případě chtěli získat pro každý dokument v kolekci index pro každou operations pole a další klíč, který obsahuje $set klíče.

Váš krok snížení by byla funkce (která nedělá nic) jednoduše definovaná jako var reduce = function() {};

Poslední krok ve vaší operaci MapReduce pak vytvoří samostatnou kolekci operací, která obsahuje objekt pole emitovaných operací spolu s polem s $set podmínky. Tuto kolekci lze pravidelně aktualizovat, když na původní kolekci spustíte operaci MapReduce. Celkem by tato metoda MapReduce vypadala takto:

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"
        }
    }
);

Dotaz na výstupní kolekci operations z operace MapReduce vám obvykle poskytne výsledek:

db.operations.findOne()

Výstup :

{
    "_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"
        }
    }
}

Poté můžete použít kurzor z db.operations.find() způsob iterace a odpovídající aktualizace vaší sbírky:

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. MongoDB $setIsSubset

  2. Spuštění Redis na Travis CI

  3. Hierarchické dotazy s Mongo pomocí $graphLookup

  4. mongodb počet různých hodnot na pole/klíč