我是MongoDb在应用程序堆栈上的新手,从LAMP (mysql后端)切换到MEAP (MongoDb后端),所以请原谅我对非关系查询的无知。
我正在尝试对MongoDb中的数据进行一些简单的分析,以向用户呈现特定关键字的趋势。
我的(简化的)集合对象结构如下:(在BSON中)
{
"_id" : ObjectId("55aae6b21e76a5d02945ccbc"),
"article" : {
"category" : [{
"title" : "Foods"
}
]},
"published" : new Date("7/17/2015 19:00:00")
}
假设每天有许多文章发表,每一篇都有许多可能的"类别",因此为简洁起见,上面的对象被截断。
我想向用户展示每天发布的类别的"前5名"计数,以便他们可以了解趋势,等等…
这是我在mongo中尝试的聚合查询,目前只是将所有类别求和,而不管发布日期:
{ "$unwind": "$article.category" },
{"$group":
{
"_id": "$article.category.title" ,
"count": { "$sum" : 1 }
}
},
{ "$sort" : { "count" : -1, "_id": 1} },
{ $limit : 5 }
生成如下结果:
{ 0: {"_id": "Foods", "count": 50},
1: {"_id": "Recipes", "count": 45},
...
}
问题:如何将结果按集合中可用的"已发布"日期分组?伪对象的结构类似于:
Date: 7/17/2015
category: Foods, count: 25
category: Recipes, count: 20
... continue top 5 results for that date
Date: 7/18/2015
category: Foods, count: 25
category: Recipes, count: 25
... continue top 5 results for that date
etc...
任何帮助这个蒙古新手是非常感激的。我一直在寻找把两个组by语句放在一起,并试图找出$push或$addtoset可以帮助我,但我不能把我的头围绕文档,使它为我的例子
您可能要查找的是Mongo日期聚合操作符。您需要做的是使用$year
和$dayOfYear
(或$month
和$dayOfMonth
)操作符按类别标题和日期对文档进行分组,这样数组中的每个元素在日期和标题方面都是唯一的。
与操作符一起,您需要对结果运行map
以将类别限制为前5个,因为我不知道在聚合调用中直接这样做的方法。
- 展开类别。
- 按类别和日期(日、年)分组计数。
- 按日期分组,并将类别(及其计数)推送到数组。
- 在结果上使用
map
来分割前5名以外的类别。
这可能是你正在寻找的查询:
db.articles.aggregate([{
"$unwind": "$article.category"
}, {
"$group": {
"_id": {
title: "$article.category.title",
year: { $year: "$published" },
day: { $dayOfYear: "$published" }
},
"count": { "$sum" : 1 }
}
}, {
$group: {
_id: {
year: "$_id.year",
day: "$_id.day"
},
categories: {
$push: { title: "$_id.title", count: "$count" }
}
}
}]).map( function (data) {
// Using map here is the best way I could think to limit
// the array size. Perhaps someone can do it all together
// But this should do the trick.
data.categories.sort( function (a, b) {
return b.count - a.count;
});
data.categories = data.categories.slice(0, 5);
return data;
});
我希望结果看起来像这样:
[{
_id: {
year: 2015,
day: 123
},
categories: [{
title: "Food",
count: 3
}, {
title: "Recipes",
count: 2
}]
}, ...]
虽然目前还不可能使用聚合框架拼接数组(此功能将很快在mongoDB 3.1.4版本中提供)但是,您仍然可以使用以下管道非常接近您想要的内容:
[
{
"$project": {
"article": "$article",
"yymmdd": {
"$dateToString": {
"date": "$published",
"format": "%Y-%m-%d"
}
}
}
},
{
"$unwind": "$article.category"
},
{
"$group": {
"count": {
"$sum": 1
},
"_id": {
"yymmdd": "$yymmdd",
"title": "$article.category.title"
}
}
},
{
"$sort": {
"_id.yymmdd": 1,
"count": -1
}
},
{
"$group": {
"item": {
"$push": {
"count": "$count",
"item": "$_id.title"
}
},
"_id": "$_id.yymmdd"
}
}
)
加上一些数据,结果集的形式为:
{u'item': [{u'count': 100, u'item': u'food'}, {u'count': 99, u'item': u'cinema'}, {u'count': 96, u'item': u'tennis'}, {u'count': 92, u'item': u'news'}, {u'count': 91, u'item': u'gossip'}, {u'count': 90, u'item': u'football'}, {u'count': 88, u'item': u'recipes'}, {u'count': 84, u'item': u'tv'}], u'_id': u'2015-05-31'}
{u'item': [{u'count': 96, u'item': u'gossip'}, {u'count': 93, u'item': u'news'}, {u'count': 92, u'item': u'food'}, {u'count': 91, u'item': u'football'}, {u'count': 87, u'item': u'tennis'}, {u'count': 84, u'item': u'recipes'}, {u'count': 84, u'item': u'cinema'}, {u'count': 82, u'item': u'tv'}], u'_id': u'2015-05-29'}
{u'item': [{u'count': 106, u'item': u'cinema'}, {u'count': 104, u'item': u'gossip'}, {u'count': 99, u'item': u'tv'}, {u'count': 98, u'item': u'news'}, {u'count': 96, u'item': u'football'}, {u'count': 94, u'item': u'food'}, {u'count': 93, u'item': u'tennis'}, {u'count': 90, u'item': u'recipes'}], u'_id': u'2015-05-25'}
{u'item': [{u'count': 85, u'item': u'football'}, {u'count': 85, u'item': u'gossip'}, {u'count': 81, u'item': u'cinema'}, {u'count': 80, u'item': u'tennis'}, {u'count': 78, u'item': u'news'}, {u'count': 74, u'item': u'recipes'}, {u'count': 70, u'item': u'food'}, {u'count': 67, u'item': u'tv'}], u'_id': u'2015-05-22'}
包含按标题出现次数排序的每日条目数组。然后在应用程序中,你可以将这个数组拼接n来获得前n个计数。您可以在这个示例(python)中查看复制它的步骤