更新阵列mongodb的内部嵌套数组[复制]

问题描述 投票:2回答:4

这个问题已经在这里有一个答案:

我有以下MongoDB的文档结构:

[
    {
        "_id": "04",
        "name": "test service 4",
        "id": "04",
        "version": "0.0.1",
        "title": "testing",
        "description": "test",
        "protocol": "test",
        "operations": [
            {
                "_id": "99",
                "oName": "test op 52222222222",
                "sid": "04",
                "name": "test op 52222222222",
                "oid": "99",
                "description": "testing",
                "returntype": "test",
                "parameters": [
                    {
                        "oName": "Param1",
                        "name": "Param1",
                        "pid": "011",
                        "type": "582",
                        "description": "testing",
                        "value": ""
                    },
                    {
                        "oName": "Param2",
                        "name": "Param2",
                        "pid": "012",
                        "type": "58222",
                        "description": "testing",
                        "value": ""
                    }
                ]
            }
        ]
    }
]

我已经能够使用$ elemMatch为了更新业务领域,但是当我试图为参数做同样的事情(修改),它似乎并没有工作。我不知道我应该看什么其他办法进入,以试图能够在特定的参数更新成功领域,其PID寻找它。

更新代码我现在有和不工作看起来是这样的:

var oid = req.params.operations;
var pid = req.params.parameters;

collection.update({"parameters":{"$elemMatch": {"pid": pid}}},{"$set": {"parameters.$.name":req.body.name, "parameters.$.description": req.body.description,"parameters.$.oName": req.body.oName,"parameters.$.type": req.body.type} }, function(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);
        }
    });
arrays node.js mongodb api
4个回答
11
投票

MongoDB的3.6及更高版本

随着MongoDB的3.6及以上提供了一个新功能,可以让你通过,以便通过在更新语句the positional filtered $\[<identifier>\]以匹配特定的元素,并应用不同的条件下使用arrayFilters语法来更新嵌套的数组:

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

MongoDB的3.4及以上:

正如在他的评论中提到@wdberkeley:

MongoDB的不支持匹配到一个数组的一个以上的电平。考虑改变您的文档模型,以便每个文档代表的操作,与常见的一组操作文件复制操作的信息。

我同意上面的,并建议重新设计架构的MongoDB的引擎不支持多个位置操作符(见Multiple use of the positional $ operator to update nested arrays

但是,如果你知道操作阵列具有参数对象必须事先更新,则更新查询将是指数:

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

编辑:

如果你想创建的飞行,即东西,这将有助于你得到的对象的索引,然后相应地修改$set条件,那么可以考虑使用MapReduce

目前,这似乎是使用聚合框架是不可能的。有链接到它的一个悬而未决的开放JIRA issue。然而,一个解决办法是可能的MapReduce。与MapReduce的基本思想是,它使用JavaScript作为其查询语言,但是这往往比聚合框架相当慢,不应被用于实时数据分析。

在你的精简操作,你需要定义几个步骤,即映射步骤(其中操作映射到集合中的所有文档,而操作可以什么都不做或发出与键和预测值的一些对象)和还原步骤(这需要发射的值的列表和它减少到一个单一的元素)。

对于地图的步骤,你最好希望集合中获得的每一个文件,该指数为每个operations阵列场和包含$set键的另一个关键。

你减少的步骤将是一个函数(什么都不做)简单地定义为var reduce = function() {};

然后在精简操作的最后一步将创建一个包含发射操作数组对象与该$set条件的区域沿单独收集操作。这个系列可以定期,当你运行在原始集合MapReduce的操作进行更新。总之,这MapReduce的方法将如下所示:

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

查询从MapReduce的操作输出收集operations通常会给你的结果:

db.operations.findOne()

输出:

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

然后,您可以使用光标从db.operations.find()方法循环,​​并相应地更新您的收藏:

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

2
投票

如果是经常变化的数据,你应该扁平化的结构和分离,从一个不起变化很大的数据。

如果是不经常更改的数据,整个数据对象不是大规模的,只是修改对象的客户端,并更新整个对象。


1
投票

我们将设法找到外阵列(i)和内部阵列(J)的索引,然后更新

collection.findById(04)
.then(result =>{
    for(let i = 0; i<result.operations.length; i++){
        if(result.operation[i]._id == "99"){
            let parameters = result.operations[i].parameters;`enter code here`
            for(let j = 0; j<parameters.length; j++){
                if(parameters[j].pid == "011"){
                    console.log("i", i);
                    console.log("j", j);
                    let data = {}
                    data["operations." + i + ".parameters." + j + ".oName"] = updateoName
                    data["operations." + i + ".parameters." + j + ".name"] = updatename
                    data["operations." + i + ".parameters." + j + ".pid"] = updatepid
                    data["operations." + i + ".parameters." + j + ".description"] = updatedescription
                    data["operations." + i + ".parameters." + j + ".value"] = updatevalue
                    console.log(data)
                    collection.update({
                        "_id": "04"
                    },{
                        $set: data
                    })
                    .then(dbModel => res.json(dbModel))
                }
            }
        }
    }
})

1
投票

与蒙戈版本3.6开始,你可以使用$ []在$ []更新嵌套数组连词

更新嵌套的数组与$连词[]

的$ []过滤位置操作,在与所有$ []位置操作者结合可以被用于更新嵌套阵列。

https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#position-nested-arrays-filtered

© www.soinside.com 2019 - 2024. All rights reserved.