如何更新嵌套数组中的值?

时间:2018-09-26 13:13:16

标签: mongodb mongodb-query

在此之前,我想说英语不是我的母语,如果我的任何解释含糊或不合理,请让我知道,我将尝试使它们更清楚。 / em>

我有一个包含一些嵌套数据的文档。当前productcustomer是数组,我希望将它们作为直接的ObjectID。

    {
            "_id" : ObjectId("5bab713622c97440f287f2bf"),
            "created_at" : ISODate("2018-09-26T13:44:54.431Z"),
            "prod_line" : ObjectId("5b878e4c22c9745f1090de66"),
            "entries" : [
                    {
                            "order_number" : "123",
                            "product" : [
                                    ObjectId("5ba8a0e822c974290b2ea18d")
                            ],
                            "customer" : [
                                    ObjectId("5b86a20922c9745f1a6408d4")
                            ],
                            "quantity" : "14"
                    },
                    {
                            "order_number" : "456",
                            "product" : [
                                    ObjectId("5b878ed322c9745f1090de6c")
                            ],
                            "customer" : [
                                    ObjectId("5b86a20922c9745f1a6408d5")
                            ],
                            "quantity" : "12"
                    }
            ]
    }

我尝试使用以下查询对其进行更新,但是由于Mongo的行为不符合我的预期,因此无法成功执行。

    db.Document.find().forEach(function(doc){
            doc.entries.forEach(function(entry){
                    var entry_id = entry.product[0]
                    db.Document.update({_id: doc._id}, {$set:{'product': entry_id}});
                    print(entry_id)
                    })
    })

通过该查询,它在对象的根中设置了product,这与我期望的不完全相同。我希望做的是遍历条目,并将每个单独的productcustomer更改为它们的ObjectId而不是一个数组。是否有可能通过mongo shell进行此操作,还是我必须寻找另一种方法来完成此操作?谢谢!

3 个答案:

答案 0 :(得分:2)

为了完成您指定的行为,您只需要稍微修改一下查询结构即可。看看here,了解有关如何实现此操作的特定MongoDB文档。我还将在下面建议对您的代码进行更新:

db.Document.find().forEach(function(doc) {
    doc.entries.forEach(function(entry, index) {
        var productElementKey = 'entries.' + index + '.product';
        var productSetObject = {};
        productSetObject[productElementKey] = entry.product[0];
        db.Document.update({_id: doc._id}, {$set: productSetObject});
        print(entry_id)
    })
})

您遇到的问题是您没有更新entries数组中的特定元素,而是向名为product的文档的顶层添加了一个新键。通常,为了设置数组中内部文档的值,需要首先指定数组键(在这种情况下为entries,然后是内部文档键(在这种情况下为product) 。由于您正在尝试在entries数组中设置特定元素,因此,您还需要在查询对象中指定索引(如上所述)。

要更新内部文档中的customer键,只需在上面的代码中将product的{​​{1}}换出即可。

答案 1 :(得分:0)

您正在尝试使用此行将属性“产品”直接添加到文档中

db.Document.update({_id: doc._id}, {$set:{'product': entry_id}});

尝试首先修改所有条目,然后使用此新条目数组更新文档。

db.Document.find().forEach(function(doc){
        let updatedEntries = [];
        doc.entries.forEach(function(entry){
            let newEntry = {};

            newEntry["order_number"] = entry.order_number;
            newEntry["product"] = entry.product[0];
            newEntry["customer"] = entry.customer[0];
            newEntry["quantity"] = entry.quantity;

            updatedEntries.push(newEntry);
       })
       db.Document.update({_id: doc._id}, {$set:{'entries': updatedEntries}});
})

答案 2 :(得分:0)

您需要枚举所有文档,然后使用每个条目中用于产品和客户的数组的第一项中的值存储一次又一次地更新文档:

db.documents.find().snapshot().forEach(function (elem) {
    elem.entries.forEach(function(entry){

        db.documents.update({
                _id: elem._id,
                "entries.order_number": entry.order_number
            }, {
                $set: {
                    "entries.$.product" : entry.product[0],
                    "entries.$.customer" : entry.customer[0]
                }
            }
        );
    });
});

您可能无需使用filtered positional operator对一个更新查询中的所有数组项进行所有更新,而不必每次进行2个更新。