【问题标题】:how to update an array inside a MongoDB collection with another array but update only changed values?如何使用另一个数组更新 MongoDB 集合中的数组但只更新更改的值?
【发布时间】:2015-06-26 11:11:45
【问题描述】:

拥有以下名为 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
    }
]
}

【问题讨论】:

    标签: javascript arrays mongodb mongodb-query


    【解决方案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 })
    

    由于“批量”API 足够智能,可以看到匹配的“iphone”上的“状态”值与已经存在的值没有什么不同(假设两者之间没有其他任何更改)并且不会将其报告为修改。

    所以让服务器来完成这项工作,因为您可以编写代码的所有智能都已经存在。

    【讨论】:

      猜你喜欢
      • 2018-03-10
      • 1970-01-01
      • 2016-08-19
      • 2021-11-23
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 1970-01-01
      • 2015-07-18
      相关资源
      最近更新 更多