首页 > 解决方案 > MongoDB - 加入两个查询结果和dense_rank

问题描述

我正在学习 MongoDB,但在理解它的概念时遇到了一些问题。

我有一个看起来像这样的集合:

db.email.findOne()
{
        "_id" : ObjectId("52af48b5d55148fa0c199646"),
        "sender" : "tori.wells@enron.com",
        "recipients" : [
                "michael@optsevents.com"
        ],
        "cc" : [ ],
        "text" : "Mr. Christman:\n\nThank you for your invitation for Dr. Lay to speak at your upcoming forum in \nFrance, the format looks wonderful.  Unfortunately, Dr. Lay has calendar \nconflicts and will be unable to participate.\n\nIf you should need further assistance, please do not hesitate to contact us.\n\nTori Wells\nExecutive Assistant",
        "mid" : "22263156.1075840285610.JavaMail.evans@thyme",
        "fpath" : "enron_mail_20110402/maildir/lay-k/_sent/101.",
        "bcc" : [ ],
        "to" : [
                "michael@optsevents.com"
        ],
        "replyto" : null,
        "ctype" : "text/plain; charset=us-ascii",
        "fname" : "101.",
        "date" : "2000-08-04 09:04:00-07:00",
        "folder" : "_sent",
        "subject" : "Wall Street Journal Millennium Forum"
}

这是安然数据库。

我正在尝试进行查询,该查询将返回列出的电子邮件,其中包含它发送的消息数量和接收的消息数量。

我设法进行了两个查询,如下所示:

db.email.aggregate({$group:{_id:"$sender",SendsAmount:{$sum:1}}},{$sort:{SendsAmount:-1}})
{ "_id" : "rosalee.fleming@enron.com", "SendsAmount" : 849 }
{ "_id" : "brown_mary_jo@lilly.com", "SendsAmount" : 82 }
{ "_id" : "leonardo.pacheco@enron.com", "SendsAmount" : 78 }

db.email.aggregate({$group:{_id:"$recipients",ReceivedAmount:{$sum:1}}},{$unwind:"$_id"},{$sort:{ReceivedAmount:-1}})
{ "_id" : "klay@enron.com", "ReceivedAmount" : 1350 }
{ "_id" : "kenneth.lay@enron.com", "ReceivedAmount" : 912 }
{ "_id" : "kenneth.lay@enron.com", "ReceivedAmount" : 78 }

如您所见,第一个返回给我的电子邮件和从它发送的电子邮件数量,第二个也返回电子邮件和它收到的电子邮件数量。

我的意思是将(?)这两个合二为一,并获得一个查询,该查询将返回如下内容:

{ "_id" : "email@enron.com", "SendsAmount" : 57, "ReceivedAmount": 43 }

我知道有 $lookup 但它只能用于两个集合,所以我的想法是从这两个查询中创建两个集合,但我觉得有更好的方法来解决我的问题。

---我的第二个问题是关于尝试做一些 MongoDB 中不存在的 DENSE_RANK。我想按已发送电子邮件的数量对电子邮件地址进行排名。

我使用了 $unwind 和 insertArrayIndex 但我得到了类似 ROW_NUMBER 的东西,这不是我想要的。

我写过这样的东西:

db.email.aggregate({$group:{"_id":"$sender",SendsAmount:{$sum:1},rank:0}},{$sort:{"ile":-1}}).forEach(function(x){
                        var howmany=0;
                        var query=db.email.aggregate({$group:{"_id":"$sender",SendsAmount:{$sum:1}}},{$match:{ile:{$gt:x.SendsAmount}}},{$group:{_id:null, HowManyGreater:{$sum:1}}});
                        query.forEach(function(y){
                            howmany=y.HowManyGreater;
                        }); 
                        howmany=howmany+1;
                        print("email: "+ x._id + " SendsAmount: " + x.SendsAmount + " rank " + howmany+1);
                    });

这给了我想要的结果,但它甚至不是文档,而只是打印的信息。我已经阅读了 MapReduce,但我不知道在这种情况下如何使用它。

标签: mongodbjoindense-rank

解决方案


如果要在聚合查询中进行所有计算,可以使用 $facet 和 $group 阶段,如下所示

db.email.aggregate([
  {
    $facet: {
      send: [
        {
          $group: {
            _id: "$sender",
            SendsAmount: {
              $sum: 1
            }
          }
        },
        {
          $sort: {
            SendsAmount: -1
          }
        }
      ],
      recieve: [
        {
          $group: {
            _id: "$recipients",
            ReceivedAmount: {
              $sum: 1
            }
          }
        },
        {
          $unwind: "$_id"
        },
        {
          $sort: {
            ReceivedAmount: -1
          }
        }
      ]
    }
  },
  {
    $project: {
      all: {
        $concatArrays: [
          "$recieve",
          "$send"
        ]
      }
    }
  },
  {
    $unwind: "$all"
  },
  {
    $group: {
      _id: "$all._id",
      ReceivedAmount: {
        $sum: {
          $cond: {
            if: {
              $gt: [
                "$all.ReceivedAmount",
                null
              ]
            },
            then: "$all.ReceivedAmount",
            else: 0
          }
        }
      },
      SendsAmount: {
        $sum: {
          $cond: {
            if: {
              $gt: [
                "$all.SendsAmount",
                null
              ]
            },
            then: "$all.SendsAmount",
            else: 0
          }
        }
      }
    }
  }
])

推荐阅读