如何用另一个数组更新MongoDB集合中的数组,但只更新更改的值?

时间:2015-06-26 11:11:45

标签: javascript arrays mongodb mongodb-query

拥有以下名为eshops的集合:

{
"_id" : ObjectId("53e87e239ae974e6a0a81004"),
"name" : "www.example.com",
"products" : [
    {
        "name" : "apple", //lets say the name key here is primary key of products
        "status" : 0
    },
    {
        "name" : "banana",
        "status" : 0
    },
    {
        "name" : "iphone",
        "status" : 0
    }
]
}

并拥有此数组

var products = [
{name: "apple", status: 1}
{name: "notebook", status: 0}
]

如果我想要以下结果,更新查询应该是什么样的?

{
"_id" : ObjectId("53e87e239ae974e6a0a81004"),
"name" : "www.example.com",
"products" : [
    {
        "name" : "apple",
        "status" : 1
    },
    {
        "name" : "banana",
        "status" : 0
    },
    {
        "name" : "iphone",
        "status" : 0
    },
    {
        "name" : "notebook",
        "status" : 0
    }
]
}

1 个答案:

答案 0 :(得分:1)

对此的全面解释是在最后阅读。

那不可能不能在一次操作中“原子地”完成,你将得到的最好的是"Bulk"操作,这是最好的方法。

var products = [
    {name: "apple", status: 1}
    {name: "notebook", status: 0}
];

var bulk = db.collection.initializeOrderedBulkOp();

products.forEach(function(product) {

    // Try to update
    bulk.find({ 
        "_id" : ObjectId("53e87e239ae974e6a0a81004"),
        "products.name": product.name
    })
    .updateOne({
        "$set": { "products.$.status": product.status }
    });

    // Try to "push"
    bulk.find({ 
        "_id" : ObjectId("53e87e239ae974e6a0a81004"),
        "products.name": { "$ne": product.name }
    })
    .updateOne({
        "$push": { "products": product }
    });

});
bulk.execute();

另一种方法是通过.findOne()或类似操作检索文档,然后更改客户端代码中的数组内容,然后.save()更改内容。

这是你不想要的,因为无法保证文档没有被“更改”,因为它被读入内存。如果其他成员被添加到数组中,那么某种操作会“覆盖”它们。

因此,循环使用多个更新的项目。至少“批量”操作会立即将这些操作发送到服务器,而无需等待单个写入的响应。

但正如你指出的那样。如果价值仍然相同怎么办?为此,您需要查看.execute()上“批量”操作的“WriteResult”响应:

WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })

因此,这里有两(2)个动作,总共发送四(4)个操作。如果数组包含一个项目,说“iphone”没有更改:

var products = [
    {name: "apple", status: 1}
    {name: "notebook", status: 0},
    {name: "iphone", status: 0 }
];

然后回复就是这样:

WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 2 })

由于“Bulk”API非常智能,可以看到匹配的“iphone”上的“status”值与已经存在的值没有区别(假设之间没有其他任何改变)并且不会将此报告为修改。

所以让服务器完成工作,因为你可以编写的所有智能都已经存在了。