Mongo构建嵌套文档数组的最佳实践

时间:2018-09-18 18:32:09

标签: mongodb

我一直在努力寻找以下问题的解决方案,并且似乎从各mongodb帖子中获得了相互矛盾的建议。我试图弄清楚如何正确表示子对象的“数组”,例如:

  1. 可以对它们进行升序设置(即在需要时通过一次操作进行更新或创建新元素)
  2. 对象的ID可以作为可搜索的值使用,而不仅仅是键(您不能真正在mongo中搜索)。

我有一个可以表示为数组的结构(代表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中,以使其全部正常工作。

0 个答案:

没有答案