mongodb聚合多个数组

mongodb聚合多个数组,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我使用的是MongoDB v3.4版。我有一个文档集合,样本数据如下: { "mlVoters" : [ {"email" : "a@b.com", "isApproved" : false} ], "egVoters" : [ {"email" : "a@b.com", "isApproved" : false}, {"email" : "c@d.com", "isApproved" : true} ] },

我使用的是MongoDB v3.4版。我有一个
文档
集合,样本数据如下:

{
    "mlVoters" : [ 
        {"email" : "a@b.com", "isApproved" : false}
    ],
    "egVoters" : [ 
        {"email" : "a@b.com", "isApproved" : false}, 
        {"email" : "c@d.com", "isApproved" : true}
    ]
},{
    "mlVoters" : [ 
        {"email" : "a@b.com", "isApproved" : false}, 
        {"email" : "e@f.com", "isApproved" : true}
    ],
    "egVoters" : [ 
        {"email" : "e@f.com", "isApproved" : true}
    ]
}
现在,如果我想要MLV投票者的不同电子邮件地址的计数:

db.documents.aggregate([
  {$project: { mlVoters: 1 } },
  {$unwind: "$mlVoters" },
  {$group: { _id: "$mlVoters.email", mlCount: { $sum: 1 } }},
  {$project: { _id: 0, email: "$_id", mlCount: 1 } },
  {$sort: { mlCount: -1 } }
])
查询结果如下:

{"mlCount" : 2.0,"email" : "a@b.com"}
{"mlCount" : 1.0,"email" : "e@f.com"}
如果我想知道egvorters的不同电子邮件地址的数量,我也会对egvorters字段进行同样的计算。该查询的结果将是:

{"egCount" : 1.0,"email" : "a@b.com"}
{"egCount" : 1.0,"email" : "c@d.com"}
{"egCount" : 1.0,"email" : "e@f.com"}
因此,我想结合这两个聚合,得到如下结果(按totalCount排序):


我该怎么做?查询应该是什么样的?谢谢。

首先在每次投票中添加一个字段
voteType
。此字段指示其类型。有了这个字段,您不需要将选票保存在两个单独的数组中
mlvorters
egvorters
;您可以将这些数组连接到每个文档的单个数组中,然后展开

此时,您每次投票都有一个文档,其中有一个字段指示文档的类型。现在,您只需通过电子邮件分组,在分组阶段,执行两个条件求和,以计算每封电子邮件中每种类型的投票数

最后,添加一个字段
totalCount
,作为其他两个计数的总和

db.documents.aggregate([
  {
    $addFields: {
      mlVoters: {
        $ifNull: [ "$mlVoters", []]
      },
      egVoters: {
        $ifNull: [ "$egVoters", []]
      }
    }
  },
  {
    $addFields: {
      "mlVoters.voteType": "ml",
      "egVoters.voteType": "eg"
    }
  },
  {
    $project: {
      voters: { $concatArrays: ["$mlVoters", "$egVoters"] }
    }
  },
  {
    $unwind: "$voters"
  },
  {
    $project: {
      email: "$voters.email",
      voteType: "$voters.voteType"
    }
  },
  {
    $group: {
      _id: "$email",
      mlCount: {
        $sum: {
          $cond: {
            "if": { $eq: ["$voteType", "ml"] },
            "then": 1,
            "else": 0
          }
        }
      },
      egCount: {
        $sum: {
          $cond: {
            "if": { $eq: ["$voteType", "eg"] },
            "then": 1,
            "else": 0
          }
        }
      }
    }
  },
  {
    $addFields: {
      totalCount: {
        $sum: ["$mlCount", "$egCount"]
      }
    }
  }
])

首先,在每次投票中添加一个字段
voteType
。此字段指示其类型。有了这个字段,您不需要将选票保存在两个单独的数组中
mlvorters
egvorters
;您可以将这些数组连接到每个文档的单个数组中,然后展开

此时,您每次投票都有一个文档,其中有一个字段指示文档的类型。现在,您只需通过电子邮件分组,在分组阶段,执行两个条件求和,以计算每封电子邮件中每种类型的投票数

最后,添加一个字段
totalCount
,作为其他两个计数的总和

db.documents.aggregate([
  {
    $addFields: {
      mlVoters: {
        $ifNull: [ "$mlVoters", []]
      },
      egVoters: {
        $ifNull: [ "$egVoters", []]
      }
    }
  },
  {
    $addFields: {
      "mlVoters.voteType": "ml",
      "egVoters.voteType": "eg"
    }
  },
  {
    $project: {
      voters: { $concatArrays: ["$mlVoters", "$egVoters"] }
    }
  },
  {
    $unwind: "$voters"
  },
  {
    $project: {
      email: "$voters.email",
      voteType: "$voters.voteType"
    }
  },
  {
    $group: {
      _id: "$email",
      mlCount: {
        $sum: {
          $cond: {
            "if": { $eq: ["$voteType", "ml"] },
            "then": 1,
            "else": 0
          }
        }
      },
      egCount: {
        $sum: {
          $cond: {
            "if": { $eq: ["$voteType", "eg"] },
            "then": 1,
            "else": 0
          }
        }
      }
    }
  },
  {
    $addFields: {
      totalCount: {
        $sum: ["$mlCount", "$egCount"]
      }
    }
  }
])

您的回答看起来很合理,但它给了我“errmsg”:“$concatarray只支持数组,不支持object”。这是因为它们不是简单的数组,而是对象数组吗?集合中是否有文档既没有
egvorters
数组,也没有
mlvorters
数组,即使是空的?这可以解释这个错误,因为在这种情况下,
$addFields:{“mlvoterns.voteType”:“ml”}
将创建一个类似于
“mlvoterns”:{“voteType”:“ml”}
的字段。如果数组不存在,可以先创建(空)数组来解决这个问题。如果不存在空数组,如何创建空数组?您的答案看起来很合理,但它给了我
“errmsg”:“$concatarray只支持数组,不支持对象”
。这是因为它们不是简单的数组,而是对象数组吗?集合中是否有文档既没有
egvorters
数组,也没有
mlvorters
数组,即使是空的?这可以解释这个错误,因为在这种情况下,
$addFields:{“mlvoterns.voteType”:“ml”}
将创建一个类似于
“mlvoterns”:{“voteType”:“ml”}
的字段。如果数组不存在,可以先创建(空)数组来解决这个问题。如果空数组不存在,如何创建空数组?