我是应用程序堆栈上MongoDb的新手,从LAMP(mysql后端)切换到MEAP(mongo后端),所以请原谅我对非关系查询的无知。
我正在尝试对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...
非常感谢您对这个mongo newb的任何帮助。我一直在考虑将两个小组的声明放在一起,并试图找出$ push或$ addtoset可以帮助我,但我无法绕过文档以使其适用于我的示例
答案 0 :(得分:0)
您可能正在寻找的是Mongo Date Aggregation Operators。您需要做的是使用$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
}]
}, ...]
答案 1 :(得分:0)
虽然目前目前无法使用聚合框架拼接数组(此功能很快将在mongoDB version 3.1.4中提供) 你仍然可以通过followng管道非常接近你想要的东西:
[
{
"$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个计数。 您可以查看重现它的步骤in this example (in python)