如何使用 MongoDB 数组更新插入?

Mar*_*sse 4 arrays mongodb mongodb-query

我正在尝试插入、更新 MongoDB 数组中的值。
我的MongoDB版本是4.0.5。

这是我的收藏:

{
    'id': 1,
    'array': [{
        'code': 'a'
    }, {
        'code': 'b'
    }]
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试进行一些 upsert 查询以插入/更新到数组中,但直到那时我才找到一个好的解决方案。

我的过滤器是:

  • 'id'(指出正确的文件)
  • 'array.code'(指向正确的数组单元)
  1. 如果文档存在于集合中但没有包含以下内容的单元格'code': 'c'
db.test.update({
        'id': 1
    }, {
        $set: {'array.$[elem].test':'ok'}
    }, {
        upsert: true,
        arrayFilters: [{'elem.code': 'c'}]
    }
)
Run Code Online (Sandbox Code Playgroud)

我没有错误,但也没有更新插入。
我想像这样在数组中插入元素:

// Desired result
{
    'id': 1,
    'array': [{
        'code': 'a'
    }, {
        'code': 'b'
    }, {
        'code': 'c'
        'test': 'ok'
    }]
}
Run Code Online (Sandbox Code Playgroud)
  1. 如果文档不存在于集合中
db.test.update({
        'id': 3
    }, {
        $set: {'array.$[elem].test':'ok'}
    }, {
        upsert: true,
        arrayFilters: [{'elem.code': 'a'}]
    }
)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我有这个错误:

WriteError: The path 'array' must exist in the document in order to apply array updates., full error: {'index': 0, 'code': 2, 'errmsg': "The path 'array' must exist in the document in order to apply array updates."}

我想用查询元素更新插入一个新文档,如下所示:

// Desired result
{
    'id': 3,
    'array': [{
        'code': 'a'
        'test': 'ok'
    }]
}
Run Code Online (Sandbox Code Playgroud)

upsert: true查询参数中的似乎不适用于数组。
我们将非常感谢您的帮助。

tur*_*hal 5

upsert 在数组中无效,如果您将 MongoDB 版本从 4.0.5 更新到 4.2,那么您可以从 MongoDB 4.2 开始使用聚合管道更新,

情况 1:如果文档存在于集合中,但没有包含以下内容的单元格'code': 'c'

var id = 2;
var item = { code: "c", test: "ok" };
Run Code Online (Sandbox Code Playgroud)

操场

情况 2:如果集合中不存在该文档:

var id = 3;
var item = { code: "a", test: "ok" };
Run Code Online (Sandbox Code Playgroud)

操场

  • $ifNull检查该字段是否不存在然后返回空
  • $cond检查输入是否code在数组中
    • 是的,然后$mep迭代循环array并检查条件是否匹配,然后更新其他字段,否则返回空对象
    • $mergeObjects将当前对象与更新的字段合并
    • 否,$concatArrays将当前array对象与新项目对象连接起来
db.collection.update(
  { "id": id },
  [{
    $set: {
      array: {
        $cond: [
          {
            $in: [item.code, { $ifNull: ["$array.code", []] }]
          },
          {
            $map: {
              input: "$array",
              in: {
                $mergeObjects: [
                  "$$this",
                  {
                    $cond: [{ $eq: ["$$this.code", "c"] }, item, {}]
                  }
                ]
              }
            }
          },
          {
            $concatArrays: [{ $ifNull: ["$array", []] }, [item]]
          }
        ]
      }
    }
  }],
  { upsert: true }
)
Run Code Online (Sandbox Code Playgroud)