在MongoDB中按查询聚合组,按日期显示前5个$count结果



我是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个,因为我不知道在聚合调用中直接这样做的方法。

我的策略是:
  1. 展开类别。
  2. 按类别和日期(日、年)分组计数。
  3. 按日期分组,并将类别(及其计数)推送到数组。
  4. 在结果上使用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)中查看复制它的步骤

相关内容

  • 没有找到相关文章

最新更新