Mongodb,使用选定的文档值使用单个操作更新同一文档中的字段
Posted
技术标签:
【中文标题】Mongodb,使用选定的文档值使用单个操作更新同一文档中的字段【英文标题】:Mongodb, use selected document value to update field in same document using single operation 【发布时间】: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 (即全名字段是第一个和最后一个的连接)。 【参考方案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”以上是关于Mongodb,使用选定的文档值使用单个操作更新同一文档中的字段的主要内容,如果未能解决你的问题,请参考以下文章