首页 > 解决方案 > 解释为什么在 upsert 上重复输入

问题描述

假设我有这个集合:

db.item.find().pretty()
{
    "_id" : ObjectId("5c5635194b6929067972b85c"),
    "name" : "car",
    "attributes" : [
        {
            "color" : "blue",
            "qty" : 10
        }
    ]
}

如果它不存在,我想在嵌入的“属性”文档中添加一个新条目,否则只进行更新。我根据 MongoDb 文档构建了以下查询来执行此操作:

db.item.update({"name":"car"}, {"$push" : {"attributes" : {"color": "red", "qty": 20}}}, upsert=true)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

这有效,我得到了这个:

db.item.find({"name":"car"}).pretty()
{
    "_id" : ObjectId("5c5635194b6929067972b85c"),
    "name" : "car",
    "attributes" : [
        {
            "color" : "blue",
            "qty" : 10
        },
        {
            "color" : "red",
            "qty" : 20
        }
    ]
}

但是,如果我再次运行查询,我会添加一个重复的条目:

db.item.update({"name":"car"}, {"$push" : {"attributes" : {"color": "red", "qty": 20}}}, upsert=true)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.item.find({"name":"car"}).pretty()
{
    "_id" : ObjectId("5c5635194b6929067972b85c"),
    "name" : "car",
    "attributes" : [
        {
            "color" : "blue",
            "qty" : 10
        },
        {
            "color" : "red",
            "qty" : 20
        },
        {
            "color" : "red",
            "qty" : 20
        }
    ]
}

为什么会这样?upsert 应该防止这种情况,还是我误解了 upsert 的功能?

标签: mongodb

解决方案


upsert 是更新或插入,如果匹配的文档存在,则更新将完成,否则插入。

在您的情况下,您已经有一个匹配的文档,因此将完成更新。$push不检查重复项,您需要使用$addToSet

如果要避免重复,则需要使用$addToSet

db.item.update(
    {"name":"car"},
    {"$addToSet" : {"attributes" : {"color": "red", "qty": 20}}},
    {upsert:true}
)

第二次更新结果

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

推荐阅读