在嵌套数组上使用$ unwind的后果?

时间:2014-12-29 17:43:48

标签: mongodb

假设我有17,000个文档,其结构与下面的文档类似:​​

{
   someInfo: "blah blah blah",
   // and another dozen or so attributes here, followed by:
   answers:[
      {
          email: "test@test.com,
          values:[
             {value: 1, label: "test1"},
             {value: 2, label: "test2"}    
          ]
      },
      {
          email: "someone@somewhere.com,
          values:[
             {value: 6, label: "test1"},
             {value: 1, label: "test2"}    
          ]
      }
   ]
}

假设我使用聚合来展开answersanswers.values,如下所示:

db.participants.aggregate(
   {$unwind: "$answers"},
   {$unwind: "$answers.values"}
);

我认为它会在内存中创建一个相当大的结果集,因为它基本上会复制父对象17,000 * # of answers * # of values次。

我一直在测试一个在开发环境中执行类似操作的查询,并且查询本身的性能很好,但是我想知道是否应该关注在生成环境中运行此问题的情况。集合可能会占用大量内存。 Mongo关于$unwind的文档介绍了它的工作原理,但没有讨论潜在的性能问题。

我应该担心在生产系统上这样做吗?它会减慢对db的其他查询吗?

1 个答案:

答案 0 :(得分:4)

由于发生数据的复制,在$unwind时认识到内存资源总是一个好主意。

使用$match将结果范围缩小到您要查找的特定文档当然是减少保存返回数据所需内存量的一种方法。

减少内存占用的另一种方法是使用$project$project允许您重新组织管道中的文档,以便您只返回您感兴趣的元素。

使用您的示例,

{
  someInfo: "blah blah blah",
  answers: [
    {
      email: "test@test.com",
      values: [
        {value: 1, label: "test1"},
        {value: 2, label: "test2"}    
      ]
    },
    {
      email: "someone@somewhere.com",
      values: [
        {value: 6, label: "test1"},
        {value: 1, label: "test2"}    
      ]
    }
  ]
}

使用

db.collection.aggregate([{ $match: { <element>: <value> }}, { $project: { _id: 0, answers: 1}}])

将删除您可能不感兴趣的someInfo和其他属性。然后您可以在展开后再次$project ...

db.collection.aggregate([
   { $match: { <element>: <value> }},
   { $project: { _id: 0, answers: 1}},
   { $unwind: "$answers"},
   { $unwind: "$answers.tags"},
   { $project: { e: "$answers.email", v: "$answers.values"}}
])

将返回相当紧凑的结果,如:

{ e: "test@test.com", v: { value: 1, label: "test1" } }
{ e: "test@test.com", v: { value: 2, label: "test2" } }
{ e: "someone@somewhere.com", v: { value: 6, label: "test1" } }
{ e: "someone@somewhere.com", v: { value: 1, label: "test2" } }

尽管单字母属性名称降低了人类的可读性,但它确实减少了由冗长的重复属性名称夸大的数据大小。