【问题标题】:Possible to avoid $unwind / aggregation on large array using $elemMatch and regular query?可以避免使用 $elemMatch 和常规查询对大型数组进行 $unwind / 聚合吗?
【发布时间】:2014-06-03 14:43:48
【问题描述】:

我有一个文档集合(称为“日志”),看起来类似于:

{
  "_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 个子文档,而不仅仅是我上面显示的两个。我现在想做的是运行一个查询,检索上面显示的vars 数组中两个子文档的val

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

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" }
});

我的问题归结为是否有一种方法可以在 find 的 <projection> 部分中多次在数组上使用 $elemMatch。如果没有,是否有另一种方法可以在不使用 $unwind 的情况下轻松检索这两个子文档?我也愿意接受其他我可能不知道的性能更高的建议。谢谢!

【问题讨论】:

    标签: mongodb


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

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

      在 2.6 版中更改:

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

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

      还有一些增强功能可能对更复杂的聚合查询很有用:

      聚合增强

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

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

      新的管道阶段:

      • $out 阶段输出到集合。
      • $redact 阶段允许额外控制访问数据。

      新的或修改的运算符:

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

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

      【讨论】:

        【解决方案3】:

        也许这行得通。

        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" }
        });
        

        希望它能如你所愿。

        【讨论】:

        • 这将在查询中添加一个额外的过滤器,但我要问的是我想在我的投影中包含来自 vars 数组的多个元素。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-06
        • 2022-01-03
        • 2016-10-26
        • 2016-12-21
        相关资源
        最近更新 更多