检索与 $group 聚合中的指定条件匹配的计数
Posted
技术标签:
【中文标题】检索与 $group 聚合中的指定条件匹配的计数【英文标题】:Retrieving a count that matches specified criteria in a $group aggregation 【发布时间】:2017-02-06 18:31:29 【问题描述】:因此,我希望将集合中的文档按特定字段分组,对于每个组的输出结果,我希望包括以下内容:
-
组中与特定查询匹配的所有文档计数(即满足某个表达式 "$Property": "Value" 的文档计数)
组中的文档总数
(奖励,因为我怀疑这不容易实现)对应于 $min/$max 累加器的文档属性
我对用于在 mongo 中查询的语法非常陌生,不太了解它是如何工作的,但经过一些研究,我设法将其归结为以下查询(请注意,我目前为我的 mongo db 使用 3.0.12 版本,但我相信我们会在几个月后升级):
db.getCollection('myCollection').aggregate(
[
$group:
_id:
GroupID: "$GroupID",
Status: "$Status"
,
total: $sum: 1 ,
GroupName: $first: "$GroupName" ,
EarliestCreatedDate: $min: "$DateCreated" ,
LastModifiedDate: $max: "$LastModifiedDate"
,
$group:
_id: "$_id.GroupID",
Statuses:
$push:
Status: "$_id.Status",
Count: "$total"
,
TotalCount: $sum: "$total" ,
GroupName: $first: "$GroupName" ,
EarliestCreatedDate: $min: "$EarliestCreatedDate" ,
LastModifiedDate: $max: "$LastModifiedDate"
]
)
基本上我要检索的是特定状态值的计数,并将它们投影到一个最终结果文档中,如下所示:
GroupName,
EarliestCreatedDate,
EarliestCreatedBy,
LastModifiedDate,
LastModifiedBy,
TotalCount,
PendingCount,
ClosedCount
其中 PendingCount 和 ClosedCount 是每个组中具有 Pending/Closed 状态的文档总数。我怀疑我需要将 $project 与其他表达式一起使用来提取此值,但我对聚合管道的理解还不够好,无法弄清楚这一点。
此外,EarliestCreatedBy 和 LastModifiedBy 分别是创建/修改与 EarliestCreatedDate 和 LastModifiedDate 对应的文档的用户。正如我所提到的,我认为检索这些值会增加另一层复杂性,所以如果没有切实可行的解决方案,我愿意放弃这个要求。
非常感谢任何建议/提示。
【问题讨论】:
【参考方案1】:您可以尝试以下聚合阶段。
$group
计算每个GroupID
的所有必要计数TotalCount
、PendingCount
和ClosedCount
分别计算$min
和$max
为EarliestCreatedDate
和LastModifiedDate
和push
到CreatedByLastModifiedBy
的所有字段,以便稍后比较每个EarliestCreatedBy
和LastModifiedBy
获取每个GroupID
$project
投影所有字段以进行响应
$filter
EarliestCreatedDate
值对CreatedByLastModifiedBy
和$map
中的数据匹配CreatedBy
到EarliestCreatedBy
和$arrayElemAt
以将数组转换为对象。
计算LastModifiedBy
的类似步骤
db.getCollection('myCollection').aggregate(
[
$group:
_id: "$GroupID",
TotalCount:
$sum: 1
,
PendingCount:
$sum:
$cond:
if:
$eq: ["Status", "Pending"]
,
then: 1,
else: 0
,
ClosedCount:
$sum:
$cond:
if:
$eq: ["Status", "Closed "]
,
then: 1,
else: 0
,
GroupName:
$first: "$GroupName"
,
EarliestCreatedDate:
$min: "$DateCreated"
,
LastModifiedDate:
$max: "$LastModifiedDate"
,
CreatedByLastModifiedBy:
$push:
CreatedBy: "$CreatedBy",
LastModifiedBy: "$LastModifiedBy",
DateCreated: "$DateCreated",
LastModifiedDate: "$LastModifiedDate"
,
$project:
_id: 0,
GroupName: 1,
EarliestCreatedDate: 1,
EarliestCreatedBy:
$arrayElemAt: [
$map:
input:
$filter:
input: "$CreatedByLastModifiedBy",
as: "CrBy",
cond:
"$eq": ["$EarliestCreatedDate", "$$CrBy.DateCreated"]
,
as: "EaCrBy",
in:
"$$EaCrBy.CreatedBy"
, 0]
,
LastModifiedDate: 1,
LastModifiedBy:
$arrayElemAt: [
$map:
input:
$filter:
input: "$CreatedByLastModifiedBy",
as: "MoBy",
cond:
"$eq": ["$LastModifiedDate", "$$MoBy.LastModifiedDate"]
,
as: "LaMoBy",
in:
"$$LaMoBy.LastModifiedBy"
, 0]
,
TotalCount: 1,
PendingCount: 1,
ClosedCount: 1
]
)
版本
$filter
在您的版本中也不可用。下面是等价的。
比较逻辑是相同的,并为每个不匹配的条目创建一个数组,其值为false
或LastModifiedBy
,否则。
下一步是使用$setDifference
将先前的数组值与数组[false]
进行比较,后者返回仅存在于第一个集合中的元素。
LastModifiedBy:
$setDifference: [
$map:
input: "$CreatedByLastModifiedBy",
as: "MoBy",
in:
$cond: [
$eq: ["$LastModifiedDate", "$$MoBy.LastModifiedDate"]
,
"$$MoBy.LastModifiedBy",
false
]
,
[false]
]
在$project
阶段之后添加$unwind
阶段以更改为对象
$unwind:"$LastModifiedBy"
计算EarliestCreatedBy
的类似步骤
【讨论】:
$$
在迭代期间访问中间变量的语法。例如 CrBy
和 EaCrBy
。在这里docs.mongodb.com/v3.2/reference/aggregation-variables
非常感谢您的帮助。我通读了它,我认为它应该适合我的需要,但它似乎对我不起作用。我相信我的 mongo db 版本 3.0.12 不支持 $arrayElemAt 表达式(对不起,我应该在我的问题中指定)。你知道在这个版本中执行类似操作的方法吗?如果没有,我现在可以凑合;我相信我们希望在几个月内将我们的数据库升级到最新版本。
不用担心。不客气。包括您的版本的更新。以上是关于检索与 $group 聚合中的指定条件匹配的计数的主要内容,如果未能解决你的问题,请参考以下文章
mongo中的高级查询之聚合操作(distinct,count,group)与数据去重
选择列表中的列无效,因为该列没有包含在聚合函数或 GROUP BY 子句中