mongodb统计子文档值

时间:2018-03-16 03:21:14

标签: mongodb mongodb-query

我非常擅长操作mongodb,只能使用简单的find()。但我有一个复杂的结构集合存储在mongodb中,版本是3.2.15。超过1000万条记录。

集合统计的主要结构如下:

{
    "_id" : BinData(3,"oQsAvnL1X01YbXCd6X1q1A=="),
    "UserId" : BinData(3,"urrg10Znz0moqFize9js+A=="),
    ... (many unimportant nodes or arrays not included for statistic),
    "Pages" : [
        {
            "Url" : {
                "Path" : "http://www.aaaa.com/",
                "QueryString" : "?tipid=2C683459F4244C2181EB697DA32AB330"
            }
        }
    ]
}

对于Pages:可以为空,也可以是每个UserId的多个值。对于UserId:可以是一条记录,也可以是多条记录。

我的问题是:我怎样才能统计以下值:

  1. 这个集合中不同的URL(pages.url.path + pages.url.querystring)怎么样?
  2. 每个用户的不同URL(pages.url.path)如何(按UserId分组)?
  3. 我要用mapreduce吗?怎么写这些功能?或者其他任何方式?

1 个答案:

答案 0 :(得分:0)

您也可以使用聚合管道。假设您的收藏名称为statistics

第一个值:

db.statistics.aggregate([
    {$project: {"Pages": 1}},
    {$unwind: "$Pages"},
    {$project: {"Url": {$concat: ["$Pages.Url.Path", "$Pages.Url.QueryString"]}}},
    {$group: {_id: "$Url"}},
    {$count: "DistinctUrls"}
]);

第二个值:

db.statistics.aggregate([
    {$project: {"UserId": 1, "Pages": 1}},
    {$unwind: "$Pages"},
    {$project: {"UserId": 1, "Url": "$Pages.Url.Path"}},
    {$group: {_id: {"UserID": "$UserId", "Url": "$Url"}},
    {$group: {_id: "$_id.UserID", "Pages": {$sum: 1}}}
]);

虽然,给定数据集大小Map-Reduce会表现得更好。

第一个值:

db.statistics.mapReduce(function() {
    this.Pages.forEach(function(Page) {
        this.emit(Page.Url.Path + Page.Url.QueryString, true);
    });
}, function(key, values) {
    return true;
}, {
    out: 'distinct_urls'
});

db.distinct_urls.count();

第二个值:

db.statistics.mapReduce(function() {
    this.Pages.forEach(function(Page) {
        this.emit(this.UserId, Page.Url.Path);
    });
}, function(key, values) {
    var newValue = [];
    values.forEach(function(value) {
        newValue = newValue.concat(value);
    });
    return newValue;
}, {
    finalize: function(key, values) {
        var pages = {};
        values.forEach(function(value) {
            pages[value] = true;
        });
        return Object.keys(pages).length;
    }
});