如何使用嵌套数据从mongodb集合中找到多个出现

时间:2014-01-29 21:32:12

标签: mongodb python-3.x mapreduce aggregation-framework

我的数据格式如下:

{'user': 'A', 'books' :['One', 'Two','Three','Seven']}
{'user': 'B', 'books' :['Two', 'Four','Five']}
{'user': 'C', 'books' :['Five', 'One','Two','Nine','Ten','Twelve']}
{'user': 'D', 'books' :['One', 'Two','Six']}

用户共同拥有的书籍意味着某种形式的合作 它们之间。我的目标是找到合作的书籍数量 (或者用户如何进行某种形式的合作vs. 那些没有任何形式合作的人)

此时我确定我不能设计一个会泄露这些信息的查询,所以我想知道,这是mongdb的mapreduce可以做的吗?如果是这样怎么样?

我之前没有做过任何mapreduce,但是看一下mongodb文档中的例子,看起来有可能用mongodb做到这一点。

3 个答案:

答案 0 :(得分:2)

始终更喜欢Aggregation Framework over map reduce。它要快得多。 你的两个问题有点不同,首先是合作的书籍:

db.books.aggregate([
    {$unwind : "$books"},
    {$group: { _id:"$books", count: {$sum: 1}}},
    {$match: {count: {$gt: 1}}},
    {$sort: {count: -1}}
])
  1. Unwind为每个用户创建一份文档并以书籍形式预订
  2. 对书籍进行分组,我们总结了合作的用户总数
  3. 过滤掉任何数量不超过1的内容。没有合作者。
  4. 反向排序只是为了好玩
  5. 将输出为:

    {
        "result" : [
                {
                        "_id" : "Two",
                        "count" : 4
                },
                {
                        "_id" : "One",
                        "count" : 3
                },
                {
                        "_id" : "Five",
                        "count" : 2
                }
        ],
        "ok" : 1
    }
    

    显示不止一次使用的图书。

    在书上与他人合作的用户更多参与:

    db.books.aggregate([
        {$unwind : "$books"},
        {$group: { _id:"$books", users: {$push: "$user"},count: {$sum: 1 }}},
        {$match:{count: {$gt: 1}}},
        {$unwind: "$users"},
        {$group: {_id: "$users", count: {$sum: 1}}},
        {$sort: {count: -1}}
    ])
    
    1. 像以前一样展开书籍数组。
    2. 再次对书籍进行分组,但这次我们将处理这些书籍的用户推送到阵列。
    3. 过滤掉任何数量不超过1的内容。没有合作者。
    4. 展开用户数组,以便我们现在有多个图书文档给用户
    5. 对用户进行分组并总结书籍
    6. 反向排序只是为了好玩
    7. 有一个结果:

      {
          "result" : [
                  {
                          "_id" : "C",
                          "count" : 3
                  },
                  {
                          "_id" : "A",
                          "count" : 2
                  },
                  {
                          "_id" : "D",
                          "count" : 2
                  },
                  {
                          "_id" : "B",
                          "count" : 2
                  }
          ],
          "ok" : 1
      }
      

      因此,这为我们提供了为每个用户合作的书籍数量。 您可以使用这些更多的交替排序并使用$ project在密钥上获得更好的名称,但我认为这给出了一些如何使用聚合框架来解决这些问题的概念。

答案 1 :(得分:1)

可以使用Aggregation framework

完成
db.books.aggregate([
   {$unwind : "$books"},
   {$group : {_id : "$books", count : {$sum : 1}}},
   {$match : {count : {$gt : 1}}},
   {$group : {_id : "total", count : {$sum : 1}}}
])

此查询计算在集合中出现多次的图书数量,如果我理解正确的话,这就是您要查找的内容。

  1. 第一次操作展开或传播书籍数组
  2. 秒计算每本书的总出场次数
  3. 第三个过滤掉只出现一次的书籍
  4. 第四个计算不止一次出现的书籍总数

答案 2 :(得分:1)

这看起来像是一个分组问题。

虽然可以使用mapreduce解决,但也可以使用聚合框架轻松解决:http://docs.mongodb.org/manual/aggregation/

我建议如下(如果你愿意,我可以“翻译”到pymongo):

db.collection.aggregate([
    {$unwind: "$books" },  
    {$group:  {_id:"$books", usedby: {$sum : 1} } },
    {$sort: {"usedby": -1} }
])

它通过$ unwind创建用户手册对,计算每个用户使用多少用户,然后按降序排序。