MongoDB - 在文档中处理多级数组

时间:2015-09-08 20:39:04

标签: mongodb meteor

我目前正在使用Meteor和MongoDB构建应用程序。我有一个3级文档结构,数组在数组中:

{
  _id: "shtZFiTeHrPKyJ8vR",
  description: "Some title",
  categories: [{
    id: "shtZFiTeHrPKyJ8vR",
    name: "Foo",
    options: [{
      id: "shtZFiTeHrPKyJ8vR",
      name: "bar",
      likes: ["abc", "bce"]
    }]
  }]
}

现在,文档可以在任何级别进行操作。意思是:

  1. description可以更改
  2. 类别可以添加/删除/重命名
  3. 可以添加/删除/重命名选项
  4. 用户可以选择选项,因此必须添加或删除
  5. 1和2很容易。添加或删除新选项也相对容易:

    MyCollection.update({ _id: id, "categories.id": categoryId }, {
      $push: {
        "categories.$.options": {
          id: Random.id
          name: optionName
        }
      }
    });
    

    但是操纵options哈希需要在javascript对象上执行此操作。这意味着我首先需要找到我的文档,迭代选项然后再写回来。

    至少那就是我现在正在做的事情。但我不喜欢这种做法。

    我在考虑的是拆分集合,至少将喜欢放入引用原始文档的自己的集合中。

    还是有另一种方式吗?我真的不喜欢我可能的解决方案。

1 个答案:

答案 0 :(得分:1)

对于这种查询,通常会使用Mongo position运算符。虽然来自文档。

  

嵌套数组

     

位置$运算符不能用于查询   遍历多个数组,例如遍历的查询   嵌套在其他数组中的数组,因为替换了$   占位符是单个值

因此,本机执行所需操作的唯一方法是使用特定索引。

db.test.update({},{$pull:{"categories.0.options.0.likes":"abc"}})

不幸的是,Mongo不允许轻松获取匹配嵌套文档的索引。

我通常会说,一旦您的查询变得困难,重新审视存储数据的方式可能是个好主意。对于你将推送数据的那些数组,Mongo可能会重新定位大量文档。这绝对是你想要最小化的东西。

因此,此时您需要将数据分成不同的文档甚至集合。

您的第一份文件将如下所示:

{
  _id: "shtZFiTeHrPKyJ8vR",
  description: "Some title",
  categories: [{
    id: "shtZFiTeHrPKyJ8vR",
    name: "Foo",
    options: ["shtZFiTeHrPKyJ8vR"]
  }]
}

通过这种方式,您可以轻松添加/删除问题中提到的选项。然后,您需要第二个集合,其中包含代表每个选项的文档。

{
  _id: "shtZFiTeHrPKyJ8vR",
  name: "bar",
  likes: ["abc", "bce"]
}

您可以详细了解参考资料here。这与您在评论中提到的内容类似。这样做的好处是您已经减少了可能的搬迁量。根据您使用数据的方式,您甚至可能会减少网络使用量。

现在对喜欢的内容进行更新很容易。

MyCollection.update({ _id: id}, {
  $push: {likes: "value"}
});

但是,这确实要求您对db进行两次查询。虽然在另一方面,你在客户端做的很少,但使用的带宽要少得多。

您需要问自己的其他一些问题是,是否真的需要嵌套深度。可能有一种更简单的方法来实现您的目标,而不需要它变得如此复杂。