{
"_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更容易(发生的事情多于阅读)。
或者我是否需要返回整个文档,并在排序/限制时推迟到客户端?
答案 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具有sort
和limit
选项,但这些选项仅适用于原始集合中具有索引的字段,因此您无法在计算字段上使用它。要获得前3名,您必须在应用程序级别对结果进行排序。当您坚持对数据库进行排序和限制时,请定义一个输出集合以存储mapReduce结果(将out选项设置为out: { replace: "temporaryCollectionName" }
),然后使用sort
查询该集合并limit
之后。
请记住,在使用中间集合时,必须确保没有两个用户将具有不同查询的MapReduces运行到同一集合中。如果有多个用户想要查看前3个列表,可以让他们查询输出集合并在常规交互中在后台执行MapReduce。