mongo可以upsert数组数据吗?

时间:2012-11-27 16:11:43

标签: node.js mongodb

我有一个像这样的mongo文件。

{
    "_id" : ObjectId("50b429ba0e27b508d854483e"),
    "array" : [
        {
            "id" : "1",
            "letter" : "a"
        },
        {
            "id" : "2",
            "letter" : "b"
        }
    ],
    "tester" : "tom"
}

我希望能够使用单个mongo命令插入和更新array,而不是在find()中使用条件,然后运行insert()update(),具体取决于物体的存在。

id是我想成为选择器的项目。所以如果我用这个更新数组:

{
    "id" : "2",
    "letter" : "c"
}

我必须使用$set声明

db.soup.update({
    "tester":"tom",
    'array.id': '2'
}, {
    $set: {
        'array.$.letter': 'c'
    }
})

如果我想在数组中插入一个新对象

{
    "id" : "3",
    "letter" : "d"
}

我必须使用$push声明

db.soup.update({
    "tester":"tom"
}, {
    $push: {
        'array': {
            "id": "3",
            "letter": "d"
        }
    }
})

我需要一个数组项的upsert。

我是否必须以编程方式执行此操作,还是可以使用单个mongo调用执行此操作?

5 个答案:

答案 0 :(得分:16)

我不知道在MongoDB 2.2中会嵌入到嵌入式数组中的选项,因此您可能需要在应用程序代码中处理此问题。

鉴于您希望将嵌入式阵列视为一种虚拟集合,您可能需要考虑将该阵列建模为单独的集合。

您无法根据嵌入数组中的字段值执行upsert,但如果嵌入文档不存在,则可以使用$addToSet插入嵌入文档:

db.soup.update({
    "tester":"tom"
}, {
    $addToSet: {
        'array': {
            "id": "3",
            "letter": "d"
        }
    }
})

这不符合数组元素id匹配的确切用例,但如果您知道预期的当前值,则可能很有用。

答案 1 :(得分:15)

我自己也遇到了这个问题。我无法找到一个通话解决方案,但是当您在数组元素中有一个唯一值时,我找到了一个双调用解决方案。首先使用$pull命令,从数组中删除元素,然后$push

db.soup.update({
    "tester":"tom"
}, {
    $pull: {
        'array': {
            "id": "3"
        }
    }
})
db.soup.update({
    "tester":"tom"
}, {
    $push: {
        'array': {
            "id": "3",
            "letter": "d"
        }
    }
})

当文档不存在,文档存在但数组中的条目不存在以及条目存在时,这应该有效。

同样,这只有在您拥有某些内容时才有效,例如本示例中的id字段,该内容在数组元素中应该是唯一的。

答案 2 :(得分:1)

如果您可以重新构建文档以使用对象而不是数组,则可以在某些情况下实现嵌入式文档集的upsert。我刚刚在another question上回答了这个问题,但为了方便我会在这里进行调整。


示例文档将是

{
    tester: 'tom',
    items: {
        '1': 'a',
        '2': 'b'
    }
}

要使用id 3和值'c'竖立项目,您需要

db.coll.update(
    { tester: 'tom' }, 
    { $set: { 'items.3': 'c' } }
)

一个缺点是查询字段名称(使用$exists查询运算符)需要扫描。您可以通过添加存储属性名称的额外数组字段来解决此问题。可以正常索引和查询该字段。 Upserts成为

db.coll.update(
    { tester: 'tom' }, 
    { 
        $set: { 'items.3': 'c' },
        $addToSet: { itemNames: 3 }
    }
)

(请记住$addToSet是O(n)。)删除属性时,您也必须从数组中提取它。

db.widgets.update(
    { tester: 'tom' }, 
    { 
        $unset: { 'items.3': true },
        $pull: { itemNames: 3 }
    }
)

答案 3 :(得分:0)

嘿,您可以使用数组过滤器选项进行操作。 你可以在这里参考 https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-arrayfilters

   db.getCollection('soup').update({'tester':tom}, { $set: { "collection.$[element].letter" : 'c' } },
   {
     arrayFilters: [ { "element.id": 2 } ]
   })

答案 4 :(得分:0)

问题是从2012年开始的。我看了一下mongo文档:https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert,罗伯·沃茨在评论中提到过,但这很稀疏。

我在这里找到了答案:https://stackoverflow.com/a/42952359/1374488