我一直在努力寻找以下问题的解决方案,并且似乎从各mongodb帖子中获得了相互矛盾的建议。我试图弄清楚如何正确表示子对象的“数组”,例如:
我有一个可以表示为数组的结构(代表A):
{
_id: 1,
subdocs: [
{ sd_id: 1, title: t1 },
{ sd_id: 2, title: t2 },
...
]
}
或作为嵌套文档(版本B)
{
_id: 1,
subdocs: {
1: { title: t1 },
2: { title: t2 },
...
}
}
我希望能够更新或插入(即upsert)新的子文档,而不必使用额外的应用程序内逻辑。
在代表B中,这很简单,因为我可以简单地使用set
$set: {subdocs.3.title: t3}
使用upsert: true
更新。
在repr A中,可以使用带有以下内容的“ arrayFilter”来更新一个现有的记录:
update({_id: 1}, {$set: {subdocs.$[i].title: t3}}, {arrayFilter: [{i.sd_id: 3}], upsert: true})
问题是,尽管上面的代码将更新现有的子对象,但如果不存在则不会创建新的子对象(即_id:3)(这不是upsert)。文档声称$ []支持upsert,但这对我不起作用。
虽然repr B确实允许更新/更新,但无法搜索子文档的id,因为它们现在是键而不是值。
上述解决方案的唯一解决方案是使用非规范化表示形式,例如该ID同时存储为键和值:
subdocs: {
1: { sd_id: 1, title: t1 },
2: { sd_id: 2, title: t2 },
...
}
但这似乎很不稳定(因为值可能不同步)。
所以我的问题是是否有办法解决?我是否可能错过了在情况A下进行高考的方法?
更新:我找到了一种解决方法,即使我不确定它是否最佳,也可以让我有效地使用reprA。它涉及使用两次写入而不是一次:
update({_id: 1, "subdocs.sd_id": {$ne: 3}}, {$push: {subdocs: {sd_id: 3}}})
update({_id: 1}, {$set: {subdocs.$[i].title: t3}}, {arrayFilter: [{i.sd_id: 3}]})
上面的第一行确保我们只插入一个带有sd_id 3的子文档(并且只有在id不存在时才起作用),而第二行更新记录(现在应该确实存在)。我可能可以将它们放在有序的bulkwrite中,以使其全部正常工作。