【问题标题】:Mongodb, use selected document value to update field in same document using single operationMongodb,使用选定的文档值使用单个操作更新同一文档中的字段
【发布时间】:2022-01-19 18:25:08
【问题描述】:

假设您正在制作一个简单的待办事项应用程序,并且您的结构如下所示:

{
[userId]: {
  nextTaskId:3,
  tasks: {
    1: "take out the trash",
    2: "pick up milk"
  }
}

添加任务时,我想使用 nextTaskId 创建一个新记录并增加它。我见过其他使用聚合函数(如 $concat 等)的示例,但这不适合我的用例。

我希望能够在我的更新中引用该字段,例如:

db.tasks.updateOne({_id:5}, {$inc:{nextId:1}, $set: {"tasks.$nextId":{"new task" }}})

该字段确实增加了,但任务键不是 3,而是 $nextId,我也尝试将其用作值,如下所示:

db.tasks.updateOne({_id:5}, {$inc:{nextId:1}, $set: {"tasks.3":{"$nextId" }}})

这也不起作用。当然,我可以通过 2 个单独的操作来做到这一点,一个是获取下一个 id 并增加它,另一个是创建新的任务记录,但我希望通过一个操作来完成。

有什么想法吗?

【问题讨论】:

  • 如果您能提供一个具体的 JSON 示例,将会很有帮助。从您的示例中,您似乎正在使用动态值作为字段名称,这通常被认为是一种反模式,建议尽可能重构您的架构。
  • 感谢您阅读问题和反馈。关于具体的 JSON 示例。我在上面有它,我没有输入 BSON 记录 ID,而是将其标记为 [userId]。后来,我有了示例查询,它们是普通的 mongosh 语法。更清楚地说,基本上我试图在我的更新中引用当前记录值,而不必执行两个单独的操作。这是针对并发问题以及性能问题。我已经看到使用聚合 fcns 完成此操作,例如使用 $concate (即全名字段是第一个和最后一个的连接)。

标签: node.js mongodb mongodb-query


【解决方案1】:

您可以将更新与聚合管道一起使用,以在单个更新语句中实现该行为。使用$objectToArray$arrayToObject 来操作tasks 数组。

db.collection.update({
  _id: 5
},
[
  {
    "$addFields": {
      "tasks": {
        "$objectToArray": "$tasks"
      }
    }
  },
  {
    "$addFields": {
      "nextTaskId": {
        $add: [
          "$nextTaskId",
          1
        ]
      },
      tasks: {
        "$concatArrays": [
          "$tasks",
          [
            {
              k: {
                $toString: "$nextTaskId"
              },
              // your input for the new task
              v: "next task"
            }
          ]
        ]
      }
    }
  },
  {
    "$addFields": {
      "tasks": {
        "$arrayToObject": "$tasks"
      }
    }
  }
])

这里是Mongo playground 供您参考。

【讨论】:

  • 哇,好的 Mongodb 向导先生。我没有意识到有 $addFields 能力。查看您的代码,它看起来像:1)第一个 $addFields 将任务 obj 转换为一个数组 2)第二个增加 nextTaskId 并添加一个新的数组元素 3)将任务数组转换回一个对象。我猜想简单地向任务 obj 添加一个属性(任务 obj)并不容易,因此使用了数组。很高兴看到如何使用 $[label] 语法轻松引用当前记录值。而且,感谢您为创建游乐场工作区而付出的额外步骤!
  • Ray,有没有一种方法可以简单地将属性添加到“任务”对象,而无需将其转换为数组、执行连接,然后返回对象?
  • 我猜测复杂性是由于您前面提到的动态键。您可以使用该 k,v 构造来解决此问题,以显式创建您要添加的哈希...我想您不能即时执行此操作
  • @paultman 是的,你是对的。如果可能,我仍然建议您更改架构。例如,如果你有一个简单的字符串数组,你可以在里面简单地$push new task。此外,从我们在这里收到的当前上下文来看,我认为没有必要维护 taskId。您可能需要重新考虑您的架构或补充更多上下文以供我们查看。
  • mongoplayground.net/p/_e6saZMWwYI 在那里我硬编码了密钥,我希望我可以使用,“$nextTaskId”
猜你喜欢
  • 1970-01-01
  • 2022-04-13
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多