MongoDB可以在此文档架构中聚合“前x个”结果吗?

时间:2013-12-16 19:38:30

标签: mongodb mapreduce aggregation-framework

{
    "_id" : "user1_20130822",
    "metadata" : {
        "date" : ISODate("2013-08-22T00:00:00.000Z"),
        "username" : "user1"
    },
    "tags" : {
        "abc" : 19,
        "123" : 2,
        "bca" : 64,
        "xyz" : 14,
        "zyx" : 12,
        "321" : 7
    }
}

鉴于上面的架构示例,有没有办法查询这个以检索顶部的“x”标签:例如,前3个“标签”按降序排序?

这可以在一个文件中吗?例如,给定日期的用户的顶部标签 如果我有多个文档需要在获得顶部之前组合在一起怎么办?例如,给定月份中用户的最高标签

我知道这可以通过使用“每个用户每个标签每天的文档”或将“标记”设置为数组来完成,但我希望能够像上面那样执行此操作,因为它可以实现$ $ inc更容易(发生的事情多于阅读)。

或者我是否需要返回整个文档,并在排序/限制时推迟到客户端?

1 个答案:

答案 0 :(得分:2)

当您使用对象键作为标记名称时,您使这种报告非常困难。 aggreation框架没有对象的$ unwind等效项。但总有MapReduce

让map-function为tags-subdocument中的每个键/值对发出一个文档。看起来应该是这样的;

var mapFunction = function() {
      for (var key in this.tags) {
          emit(key, this.tags[key]);
      }
}

然后,您的reduce函数会对相同键的值进行求和。

var reduceFunction = function(key, values) {
    var sum = 0;
    for (var i = 0; i < values.length; i++) {
        sum += values[i];
    }
    return sum;
}

完整的MapReduce命令如下所示:

 db.runCommand(
           {
             mapReduce: "yourcollection", // the collection where your data is stored
             query: { _id : "user1_20130822" }, // or however you want to limit the results
             map: mapFunction,
             reduce: reduceFunction,
             out: "inline", // means that the output is returned directly. 
           }
         )

这将以不可预测的顺序返回所有标签。 MapReduce具有sortlimit选项,但这些选项仅适用于原始集合中具有索引的字段,因此您无法在计算字段上使用它。要获得前3名,您必须在应用程序级别对结果进行排序。当您坚持对数据库进行排序和限制时,请定义一个输出集合以存储mapReduce结果(将out选项设置为out: { replace: "temporaryCollectionName" }),然后使用sort查询该集合并limit之后。

请记住,在使用中间集合时,必须确保没有两个用户将具有不同查询的MapReduces运行到同一集合中。如果有多个用户想要查看前3个列表,可以让他们查询输出集合并在常规交互中在后台执行MapReduce。