【问题标题】:Mongodb aggregate $add value by _idMongodb 通过 _id 聚合 $add 值
【发布时间】:2014-08-29 15:20:23
【问题描述】:

我正在尝试创建观看次数最多的元素(作者)的聚合。

这是我收集的用户:

{
  "_id" : ObjectId("54008ac8145a6cc5058b456b"),
  "history" : {
    "authors" : [
      {
        "name" : "michou",
        "count" : {
          "all" : NumberLong(1),
          "2014" : NumberLong(1),
          "201408" : NumberLong(1),
          "2014w35" : NumberLong(1)
        }
      }
    ]
  }
}
{
  "_id" : ObjectId("54008ac8145a6ccb058b4570"),
  "history" : {
    "authors" : [
      {
        "name" : "petitBonhommeEnMousse",
        "count" : {
          "all" : NumberLong(2),
          "2014" : NumberLong(2),
          "201408" : NumberLong(2),
          "2014w35" : NumberLong(2)
        }
      },
      {
        "name" : "lordVador",
        "count" : {
          "all" : NumberLong(1),
          "2014" : NumberLong(1),
          "201408" : NumberLong(1),
          "2014w35" : NumberLong(1)
        }
      }
    ]
  }
}
{
  "_id" : ObjectId("54008ac8145a6ccf058b456c"),
  "history" : {
    "authors" : [
      {
        "name" : "lordVador",
        "count" : {
          "all" : NumberLong(1),
          "2014" : NumberLong(1),
          "201408" : NumberLong(1),
          "2014w35" : NumberLong(1)
        }
      }
    ]
  }
}

我想获得的是用户在过去三周内看到作者的次数列表。

为此,当用户看到一个页面时,我会增加键“2014w35”、“2014w36”的值...(一年中的星期数)。

这是第一次尝试:

db.users.aggregate(
  [
    { $match: { history_updated: "20140829" } },
    { $unwind: "$history.authors" },
    { $group :
      {
        "_id" : "$history.authors.name",
        "total2014w35" : {"$sum"  : "$history.authors.count.2014w35"},
        "total2014w34" : {"$sum"  : "$history.authors.count.2014w34"},
        "total2014w33" : {"$sum"  : "$history.authors.count.2014w33"}
      }
    },
    { $project: {
        "_id" : 1,
        "total" : {
          $add : [
            "$total2014w35",
            "$total2014w34",
            "$total2014w33"
          ]
        }
      }
    }
  ]
)

返回查看作者的列表以及查看次数,但不按用户分隔。这是总数:

{ "_id" : "lordVador", "total" : NumberLong(2) }
{ "_id" : "petitBonhommeEnMousse", "total" : NumberLong(2) }
{ "_id" : "michou", "total" : NumberLong(1) }

我的第二次尝试是按 _id 分组:

db.users.aggregate(
  [
    { $match: { history_updated: "20140829" } },
    { $unwind: "$history.authors" },
    {
      $group :
      {
        "_id" : "$_id",
        ....

当然,这会返回用户查看的作者总数。但没有作者详细信息。

{ "_id" : ObjectId("54008ac8145a6ccb058b4570"), "total" : NumberLong(3) }
{ "_id" : ObjectId("54008ac8145a6ccf058b456c"), "total" : NumberLong(1) }
{ "_id" : ObjectId("54008ac8145a6cc5058b456b"), "total" : NumberLong(1) }

我想要的是两者的结合。我想为每个用户(集合中的文档)提供作者列表,每个用户在过去 3 周内看到他/她的次数。

类似:

{ "_id" : ObjectId("54008ac8145a6ccb058b4570"), [{ "lordVador" : NumberLong(3) },{ "michou" : NumberLong(1) } ] }
{ "_id" : ObjectId("54008ac8145a6ccf058b456c"), [{ "petitBonhommeEnMousse" : NumberLong(1) } ] }
{ "_id" : ObjectId("54008ac8145a6cc5058b456b"), [{ "lordVador" : NumberLong(1) } ] }

你们中有人知道如何混合它们吗?

【问题讨论】:

  • 我不明白你在追求什么。请解释得更清楚。什么是用户?您作为示例提供的每个文档都代表一个用户?在这种情况下,您想要的信息似乎几乎就在原始文档中。像“2014w35”这样的奇怪键是什么?你为什么(显然)使用值作为键?你为什么不使用日期?
  • 嗨,如果不清楚,抱歉。我更新了我的问题。是的,集合中的每个文档都是一个用户。我想为每个用户(集合中的文档)提供作者列表,其中每个用户在过去 3 周内看到他/她的次数。 2014w35 代表 2014 年的第 35 周。我没有使用日期,因为我按周存储它。

标签: mongodb aggregation-framework mongodb-php


【解决方案1】:

使用聚合框架,您无法获得作者姓名和他们的人数之间的映射。最多你可以得到,两个不同的数组被认为是关联的:

db.user.aggregate([
{$match: {"history_updated": "20140829" } },
{$unwind:"$history.authors"},
{$group:{"_id":"$_id","authors":{$push:"$history.authors.name"},
         "visits_last_three_mnths":{$push:{$add:["$history.authors.count.201408","$history.authors.count.2014w35"]}}}
}
])

示例 o/p:(已更改 id、数字,从您的示例中删除了一个用户)

{ "_id" : 2, "authors" : [ "petitBonhommeEnMousse", "lordVador" ], "visits_last_three_mnths" : [75,150 ] }
{ "_id" : 1, "authors" : [ "michou" ], "visits_last_three_mnths" : [ 300 ] }

注意:“authors”和“visits_last_three_mnths”数组之间的关联性由它们的索引保留。但是,您想要的结果可以通过 Map-Reduce 实现。

我使用的修改后的数据集,

db.user.insert({
  "_id" : 1,
  "history" : {
    "authors" : [
      {
        "name" : "michou",
        "count" : {
          "all" : 400,
          "2014" : 300,
          "201408" : 200,
          "2014w35" : 100
        }
      }
    ]
  }
});
db.user.insert({
  "_id" : 2,
  "history" : {
    "authors" : [
      {
        "name" : "petitBonhommeEnMousse",
        "count" : {
          "all" : 200,
          "2014" : 100,
          "201408" : 50,
          "2014w35" : 25
        }
      },
      {
        "name" : "lordVador",
        "count" : {
          "all" : 300,
          "2014" : 200,
          "201408" : 100,
          "2014w35" : 50
        }
      }
    ]
  }
});

这是我使用 Map reduce 进行的拍摄(使用与上述相同的数据集),希望对您有所帮助:

var map = function(){emit(this._id,{"author":this.history.authors});}
var reduce = function(userid,authors_arr){
var reduced = {"user_views":[]};
for(var i in authors_arr)
{
    var author_array = authors_arr[i];
    var authors = author_array.author;
    for(var j in authors)
    {
        var author = authors[j];
        reduced.user_views.push({"author_name":author.name,"views":author.count.all});
    }
}
return reduced;
}

db.user.mapReduce(map,reduce,{ out: "output" }) 

[
  {
    "_id": 1,
    "value": {
      "user_views": [
        {
          "author_name": "michou",
          "views": 400
        }
      ]
    }
  },
  {
    "_id": 2,
    "value": {
      "user_views": [
        {
          "author_name": "petitBonhommeEnMousse",
          "views": 200
        },
        {
          "author_name": "lordVador",
          "views": 300
        }
      ]
    }
  }
]

注意:您需要更改密钥命名约定,例如,'201408' 不是有效的 java 脚本属性。 更改后,您可以修改“减少”功能以获得每周观看次数的总和。

【讨论】:

  • 嗨,你的例子不起作用,它什么也没返回。但我认为你是对的,我将使用 map-reduce。聚合框架运行速度更快,但似乎无法实现我想要的。
  • 是的,如果你直接复制粘贴就不会了。它包含指示多周计数添加的指示符(“,..”)。现在已经删除了。此外,我必须在本地对您的代码进行一些更改,例如更改 ID、删除一些记录。已包含我使用的数据集。是的,Map-reduce 是解决方案。
  • 啊,不,不是那样,当然我改变了......只是我拼错了集合的名称......是的,它的作品。但我不能按最常用的或限制为最常用的三个来排序。我将使用 map-reduce 比。谢谢。
  • 没问题。我添加了一个使用 Map reduce 的实现,希望您可以以此为起点来构建您的解决方案。
  • 嗯..这很尴尬..如果我完全按照您的 map-reduce 进行操作,则输出返回:{ "_id" : ObjectId("54008ac8145a6cc5058b456b"), "value" : { "author" : [ { "name" : "michou", "count" : { "all" : NumberLong(1), "2014" : NumberLong(1), "201408" : NumberLong(1), "2014w35" : NumberLong(1) } } ] } } 我搜索但没有找到这些数据到底是如何进入输出的!没有 user_views 或任何东西的痕迹。顺便说一句,我不明白你为什么将 this.history.authors 嵌入到 emit() 中的对象中?
【解决方案2】:

也许您可以在第二次尝试时尝试“$addToSet”。将作者和阅读编号添加到集合中。如果作者对每个用户都是唯一的,“$push”就可以了。 http://docs.mongodb.org/manual/reference/operator/aggregation/push/

【讨论】:

    猜你喜欢
    • 2015-03-28
    • 2023-04-11
    • 2016-12-24
    • 2015-05-08
    • 1970-01-01
    • 2016-08-16
    • 2015-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多