MongoDB $ addToSet替换

时间:2016-09-29 17:33:08

标签: arrays mongodb mongodb-query

我有一份如下文件:

{
    _id: "00112233",
    array: [
        {
            _id: "potatoes",
            amount: 5
        },
        {
            _id: "carrots",
            amount: 6
        }
    ]
}

我需要更新或推送文档,这样如果数组中有一个文档,则会被替换,如果没有,则会被推送。
如果我尝试进行这样的更新:

db.collection.update(
    { _id: "00112233" },
    {
        "$push": { "array": { "$each": [
            {
                _id: "potatoes",
                amount: 6
            },
            {
                _id: "apples",
                amount: 2
            }
        ]}}
    }
)

在数据库中,我会找到两个“土豆”字段。但如果我尝试用“addToSet”替换“推”,我将不会更新“土豆”字段。
有什么方法可以只在一个查询中执行此操作吗?

3 个答案:

答案 0 :(得分:2)

不幸的是,您无法达到单个更新操作所期望的结果。

addToSet不适用于此方案,因为该阵列具有嵌入的文档。 addToSet检查属性名称和值是否匹配。如果找到匹配,则不执行任何操作。如果未找到匹配项,则会将数据添加到数组属性中。

在上述“土豆”的情况下,土豆的数量值不匹配。所以它将一个新元素插入到数组中。所以结果有两个土豆有2个不同的值。

{
                _id: "potatoes",
                amount: 6
            }

您可能需要执行两次更新操作。

1)使用$set

更新数组字段的值(如果存在)
db.collection.update(
 { _id: "00112233", "array._id": "potatoes"},

 {
        "$set": { "array.$": 
            {
                _id: "potatoes",
                amount: 7
            }

        },

    }

);

2)使用$addToSet

将新元素添加到数组字段(如果它不存在)
db.collection.update(
 { _id: "00112233"},

 {
        "$addToSet": { "array": 
            {
                _id: "apples",
                amount: 7
            }

        },

    }

);

答案 1 :(得分:0)

您需要使用$set代替$push/$addToSet

https://docs.mongodb.com/manual/reference/operator/update/set/

答案 2 :(得分:0)

遇到类似的问题并尝试了概念探索的方法,它确实起作用了。我的模式如下

neighbors=[]

我想更新以下matchInstances子文档,如果存在匹配项,其伪关键字与顶级(父文档)伪关键字相同,而没有 复制值,如果不存在则在matchInstances子文档中创建一个新条目。

 const MatchInstanceSchema = new Schema({
       _id: false,
       pseudoKey: { type: String, required: true, unique: true },
       service: { type: String, required: true },
       region: { type: String, required: true },
       team1: {
         name: { type: String, required: true },
         price: { type: String, required: true }
       },
       team2: {
         name: { type: String, required: true },
         price: { type: String, required: true }
       },
       drawPrice: { type: String, required: true },
       url: { type: String, required: true }
    })

const MatchSchema = new Schema({
      pseudoKey: { type: String, required: true, unique: true },
      sport: { type: String, required: true },
      league: { type: String, required: true },
      date: { type: Date, required: true },
      team1: { type: String, required: true },
      team2: { type: String, required: true },
      matchInstances: [MatchInstanceSchema]
   })

这是我的解决方法

{
"_id" : ObjectId("5b47d47e7fd01d29178aa3a5"),
"pseudoKey" : "newcastle-tottenham",
"sport" : "Soccer",
"league" : "Premier League",
"date" : ISODate("2018-08-11T11:30:00.000Z"),
"team1" : "Newcastle",
"team2" : "Tottenham",
"matchInstances" : [ 
    {
        "team1" : {
            "name" : "Newcastle",
            "price" : "74.6"
        },
        "team2" : {
            "name" : "Tottenham",
            "price" : "2.06"
        },
        "pseudoKey" : "newcastle-tottenham",
        "service" : "Betin",
        "region" : "Kenya",
        "drawPrice" : "3.45",
        "url" : "https://web.betin.co.ke/Sport/SubEventOdds.aspx?SubEventID=16701401"
    }
]