假设我有一个名为“posts”的集合(实际上它是一个更复杂的集合,帖子太简单了),具有以下结构:
> db.posts.find()
{ "_id" : ObjectId("50ad8d451d41c8fc58000003"), "title" : "Lorem ipsum", "author" :
"John Doe", "content" : "This is the content", "tags" : [ "SOME", "RANDOM", "TAGS" ] }
我希望这个集合能够跨越数十万甚至数百万,我需要按标签查询帖子并按标签对结果进行分组并显示分页结果。这就是聚合框架的用武之地。我计划使用aggregate()方法来查询集合:
db.posts.aggregate([
{ "$unwind" : "$tags" },
{ "$group" : {
_id: { tag: "$tags" },
count: { $sum: 1 }
} }
]);
要抓住的是创建分页符,我需要知道输出数组的长度。我知道你可以这样做:
db.posts.aggregate([
{ "$unwind" : "$tags" },
{ "$group" : {
_id: { tag: "$tags" },
count: { $sum: 1 }
} }
{ "$group" : {
_id: null,
total: { $sum: 1 }
} }
]);
但这会丢弃先前管道(第一组)的输出。有没有办法在保留每个管道输出的同时组合两个操作?我知道整个聚合操作的输出可以用某种语言转换为数组并计算内容,但管道输出可能有可能超过16Mb的限制。此外,仅仅为了获得计数而执行相同的查询似乎是浪费。
那么获取文件结果并同时计算可能吗?任何帮助表示赞赏。
答案 0 :(得分:32)
$project
将tag
和count
保存到tmp
$push
或addToSet
将tmp
存储到您的data
列表中。代码:
db.test.aggregate(
{$unwind: '$tags'},
{$group:{_id: '$tags', count:{$sum:1}}},
{$project:{tmp:{tag:'$_id', count:'$count'}}},
{$group:{_id:null, total:{$sum:1}, data:{$addToSet:'$tmp'}}}
)
输出:
{
"result" : [
{
"_id" : null,
"total" : 5,
"data" : [
{
"tag" : "SOME",
"count" : 1
},
{
"tag" : "RANDOM",
"count" : 2
},
{
"tag" : "TAGS1",
"count" : 1
},
{
"tag" : "TAGS",
"count" : 1
},
{
"tag" : "SOME1",
"count" : 1
}
]
}
],
"ok" : 1
}
答案 1 :(得分:3)
除了计算所有标签之外,我不确定你需要聚合框架,例如:
db.posts.aggregate(
{ "unwind" : "$tags" },
{ "group" : {
_id: { tag: "$tags" },
count: { $sum: 1 }
} }
);
对于通过每个标记进行分页,您可以使用常规查询语法 - 如下所示:
db.posts.find({tags: "RANDOM"}).skip(10).limit(10)