mongodb mongo可以upsert数组数据吗?

uxhixvfz  于 2023-02-15  发布在  Go
关注(0)|答案(6)|浏览(169)

我有一个蒙戈文件像这样。

{
    "_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调用来完成这一操作?

vmjh9lq9

vmjh9lq91#

有了mongo 4.2 adding support for aggregation pipelines in update,我可以使用$set$concatArrays$ifNull$filter在一次调用中将这些内容组合在一起。

db.soup.updateOne(
  { tester: 'tom' },
  [
    {
      $set: {
        array: {
          $concatArrays: [
            [{ id: '2', letter: 'c' }],
            {
              $ifNull: [
                {
                  $filter: {
                    input: '$array',
                    as: 'item',
                    cond: {
                      $ne: [
                        '$$item.id',
                        '2',
                      ],
                    },
                  },
                },
                [],
              ],
            },
          ],
        },
      },
    },
  ],
)

这将替换id'2'的项,如果数组中没有其他项匹配,则将追加该项。

1mrurvl1

1mrurvl12#

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

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

当文档不存在、文档存在但数组中的条目不存在以及条目存在时,这应该起作用。
同样,只有当您有一些东西(如本例中的id字段)在数组的元素之间应该是唯一的时,这才有效。

pxq42qpu

pxq42qpu3#

我不知道像MongoDB2.2中那样有一个选项会upsert到嵌入式数组中,因此您可能必须在应用程序代码中处理这个问题。
如果您希望将嵌入式数组视为某种虚拟集合,则可能希望考虑将数组建模为单独的集合。
不能基于嵌入数组中的字段值进行upsert,但是如果嵌入文档不存在,可以使用$addToSet插入它:

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

这并不完全适合按数组元素的id进行匹配的情况,但是如果您知道预期的当前值,这可能会很有用。

shyt4zoc

shyt4zoc4#

在某些情况下,如果您可以重新构造文档以使用对象而不是数组,则可以实现嵌入式文档集的upsert。我刚刚在另一个问题上回答了这个问题,但为了方便起见,这里将对其进行修改。
示例文档如下

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

要向上插入id 3且值为'c'的项,可以执行以下操作

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

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

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

(Keep注意$addToSet是O(n)。)当删除属性时,还必须将其从数组中拉出来。

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

x4shl7ld5#

你可以使用数组过滤器选项。你可以参考这里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 } ]
   })
2w3rbyxf

2w3rbyxf6#

这个问题来自2012年,我看了一下mongo的文档:Rob Watts在一篇评论中提到的https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert,但非常稀疏。
我在这里找到了答案:https://stackoverflow.com/a/42952359/1374488

相关问题