使用$ elemMatch和常规查询可以避免大数组上的$ unwind / aggregation?

时间:2014-06-03 14:43:49

标签: mongodb

我有一组文件(称之为“日志”),看起来与此类似:

{
  "_id" : ObjectId("52f523892491e4d58e85d70a"),
  "ds_id" : "534d35d72491de267ca08e96",
  "eT" : NumberLong(1391784000),
  "vars" : [{
      "n" : "ActPow",
      "val" : 73.4186401367188,
      "u" : "kWh",
      "dt" : "REAL",
      "cM" : "AVE",
      "Q" : 99
    }, {
      "n" : "WinSpe",
      "val" : 3.06327962875366,
      "u" : "m/s",
      "dt" : "REAL",
      "cM" : "AVE",
      "Q" : 99
    }]
}

vars数组包含大约150个子文档,而不仅仅是我上面显示的两个子文档。我现在要做的是运行一个查询,该查询检索上面显示的val数组中两个子文档的vars

使用聚合框架,我已经能够提出以下内容:

db.logs.aggregate( [ 
    { $match : 
        { ds_id: "534d35d72491de267ca08e96", 
          eT: { $lt : 1391784000 }, 
          vars: { $elemMatch: { n: "PowCrvVld", val: 3 }}
        }
    }, 
    { $unwind : "$vars" }, 
    { $match :
        { "vars.n" : { $in : ["WinSpe", "ActPow"] }}, 
        { $project : { "vars.n" : 1, N : 1}
    } 
]);

虽然这有效,但在运行较大的查询时,我遇到了16MB的限制。看到我在vars数组中有大约150个子文档,如果可能,我还想避免使用$unwind

使用常规查询并使用$elemMatch我已经能够检索其中一个值:

db.logs.TenMinLog.find({
    ds_id : "534d35d72491de267ca08e96",
    eT : { $lt : 1391784000 },
    vars : { $elemMatch : { n : "PowCrvVld", val : 3 }
    }
}, {
    ds_id : 1,
    vars : { $elemMatch : { n : "ActPow", cM : "AVE" }
});

我的问题是,如果有一种方法可以在查找的<projection>部分多次对数组使用$ elemMatch。如果没有,是否有另一种方法可以轻松检索这两个子文档而不使用$ unwind?我也愿意接受我可能不了解的更高效的其他建议。谢谢!

3 个答案:

答案 0 :(得分:1)

如果您使用的是MongoDB 2.6,则可以使用$redact运算符修剪vars数组中的元素。

在MongoDB 2.6中,您还可以将结果作为游标返回,以避免16MB的限制。来自文档:

  

在MongoDB 2.6中,aggregate命令可以将结果作为游标或结果返回   将结果存储在一个不受大小限制的集合中   限制。 db.collection.aggregate()返回一个游标并可以返回   任何大小的结果集。

答案 1 :(得分:1)

我强烈考虑迁移到MongoDB 2.6版本。聚合已得到增强,可返回一个消除16MB文档限制的游标:

  

在版本2.6中更改:

     

db.collection.aggregate()方法返回一个游标并可以返回   任何大小的结果集。以前的版本在a中返回所有结果   单个文档,结果集的大小限制为16   兆字节。

http://docs.mongodb.org/manual/core/aggregation-pipeline/

此外,您可能会发现许多增强功能可用于更复杂的聚合查询:

  

聚合增强功能

     

聚合管道添加了返回任何结果集的功能   大小,通过返回游标或将输出写入a   采集。此外,聚合管道支持变量   并添加新操作来处理集合和编辑数据。

     

db.collection.aggregate()现在返回一个游标,它启用了   聚合管道返回任何大小的结果集。聚合   管道现在支持解释操作以帮助分析   聚合操作。聚合现在可以使用更高效   基于外部磁盘的排序过程。

     

新的管道阶段:

     
      
  • $ out stage to output to a collection。
  •   
  • $ redact阶段允许其他控件访问数据。
  •   
     

新的或修改过的运营商:

     
      
  • 设置表达式运算符。
  •   
  • $ let和$ map运算符允许使用变量。
  •   
  • $ literal operator和$ size operator。
  •   
  • $ cond表达式现在接受对象或数组。
  •   

http://docs.mongodb.org/manual/release-notes/2.6/

答案 2 :(得分:0)

也许这有效。

db.logs.TenMinLog.find({
    ds_id : "534d35d72491de267ca08e96",
    eT : { $lt : 1391784000 },
    vars : { $or: [{ $elemMatch : { n : "PowCrvVld", val : 3 },
                   { $elemMatch : { n : <whatever>, val : <whatever> }]
           }
    }
}, {
    ds_id : 1,
    vars : { $elemMatch : { n : "ActPow", cM : "AVE" }
});

希望它能按你的意愿运作。