如何在 mongodb 聚合中同时计算文档总数和分组计数?

How can i count total documents and also grouped counts simultanously in mongodb aggregation?

我在 mongodb 集合中有一个名为 visitorsSession 的数据集,例如

{ip : 192.2.1.1,country : 'US', type : 'Visitors',date : '2019-12-15T00:00:00.359Z'},
{ip : 192.3.1.8,country : 'UK', type : 'Visitors',date : '2019-12-15T00:00:00.359Z'},
{ip : 192.5.1.4,country : 'UK', type : 'Visitors',date : '2019-12-15T00:00:00.359Z'},
{ip : 192.8.1.7,country : 'US', type : 'Visitors',date : '2019-12-15T00:00:00.359Z'},
{ip : 192.1.1.3,country : 'US', type : 'Visitors',date : '2019-12-15T00:00:00.359Z'}

我正在使用这个 mongodb 聚合

[{$match: {
  nsp : "/hrm.sbtjapan.com",
  creationDate : {
  $gte: "2019-12-15T00:00:00.359Z",
  $lte: "2019-12-20T23:00:00.359Z"
 },
 type : "Visitors"
 }}, {$group: {
 _id : "$country",
 totalSessions : {
   $sum: 1
  }

  }}, {$project: {
    _id : 0,
    country : "$_id",
    totalSessions : 1
   }}, {$sort: {
  country: -1
 }}]

使用以上 aggregation 我得到这样的结果

[{country : 'US',totalSessions  : 3},{country : 'UK',totalSessions  : 2}]

但我也统计了访问者总数以及 totalVisitors : 5 这样的结果 我如何在 mongodb aggregation 中执行此操作?

您可以使用 $facet 聚合阶段一次性计算访问者总数 以及按国家/地区 的访问者:

db.visitorsSession.aggregate( [
  {
      $match: {
          nsp : "/hrm.sbtjapan.com",
          creationDate : {
              $gte: "2019-12-15T00:00:00.359Z",
              $lte: "2019-12-20T23:00:00.359Z"
          },
          type : "Visitors"
      }
  },
  { 
      $facet: {
            totalVisitors: [
                { 
                    $count: "count" 
                }
            ],
            countrySessions: [
                {
                    $group: {
                        _id : "$country", 
                        sessions : { $sum: 1 }
                    }
                },
                { 
                    $project: { 
                        country: "$_id", 
                        _id: 0, 
                        sessions: 1 
                    } 
                }
            ],
      }
  },
 { 
      $addFields: { 
          totalVisitors: { $arrayElemAt: [ "$totalVisitors.count" , 0 ] },
      } 
  }
] )

输出:

{
        "totalVisitors" : 5,
        "countrySessions" : [
                {
                        "sessions" : 2,
                        "country" : "UK"
                },
                {
                        "sessions" : 3,
                        "country" : "US"
                }
        ]
}

您最好使用两个查询来执行此操作。

要保存聚合后的两次数据库往返,可以使用 IMO 有点冗长(如果文档非常大,可能会有点贵)来计算文档。

思路:就是有一个$group at the top to count documents and preserve the original documents using $push and $$ROOT. And then before other matches/filter ops $unwind创建的原始文档数组。

db.collection.aggregate([
  {
    $group: {
      _id: null,
      docsCount: {
        $sum: 1
      },
      originals: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $unwind: "$originals"
  },
  { $match: "..." }, //and other stages on `originals` which contains the source documents
  {
    $group: {
      _id: "$originals.country",
      totalSessions: {
        $sum: 1
      },
      totalVisitors: {
        $first: "$docsCount"
      }
    }
  }
]);

示例 O/P: Playground Link

[
  {
    "_id": "UK",
    "totalSessions": 2,
    "totalVisitors": 5
  },
  {
    "_id": "US",
    "totalSessions": 3,
    "totalVisitors": 5
  }
]