{
"_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更容易(其中发生的比读取多得多(。
还是我需要返回整个文档,并在排序/限制时服从客户端?
当您使用对象键作为标签名称时,会使这种报告变得非常困难。对于对象,聚合框架没有$unwind等效项。但总有MapReduce。
让您的映射函数为标签子文档中的每个键/值对发出一个文档。它应该看起来像这样;
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有一个sort
和一个limit
选项,但这些只适用于在原始集合中具有索引的字段,因此您不能在计算字段上使用它。若要仅获取前 3 个,必须在应用程序级别对结果进行排序。当您坚持对数据库进行排序和限制时,请定义一个输出集合来存储 mapReduce 结果(将 out-option 设置为 out: { replace: "temporaryCollectionName" }
(,然后使用 sort
和 limit
查询该集合。
请记住,当您使用中间集合时,必须确保没有两个用户使用不同的查询运行 MapReduce到同一个集合。当你有多个用户想要查看你的前3个列表时,你可以让他们查询输出集合,并定期在后台执行MapReduce。