我想仅使用 MongoDB 聚合来执行任务,而不需要额外的代码。这与我们运行聚合的环境有关。
我们有一个
users
系列。在我们的应用程序中,可以创建和删除用户。 createdAt
字段包含创建用户的日期,deletedAt
字段包含删除用户的日期。
我想创建一个聚合,能够计算我们每月拥有的活跃(未删除)不同用户的数量,从创建第一个用户的月份开始,到现在为止。
用更书呆子的话来说,我想找到日期范围的数量,每个日期范围从
createdAt
开始到 deletedAt
结束,与每个月相交,从创建第一个用户的月份开始。我们希望避免手动输入每个月,因为这会破坏我们想要实现的自动化,所以我们需要以编程方式获取月份,这样聚合现在和将来都可以工作。
假设我的收藏
users
有这三个条目:
{
"_id" : ObjectId("5fbf2996846471279461asd87"),
"createdAt" : ISODate("2023-07-26T04:05:36.314Z"),
"deletedAt" : ISODate("2023-11-15T07:06:36.314Z"),
}, {
"_id" : ObjectId("6fbf2996846471279461asd87"),
"createdAt" : ISODate("2023-09-05T09:05:36.314Z"),
}, {
"_id" : ObjectId("7fbf2996846471279461asd87"),
"createdAt" : ISODate("2023-10-14T04:05:36.314Z"),
"deletedAt" : ISODate("2023-10-15T07:06:36.314Z"),
},
所以我希望输出是这样的:
{
"createdAt": "2023-07",
"count": 1,
}, {
"createdAt": "2023-08",
"count": 1,
}, {
"createdAt": "2023-09",
"count": 2,
}, {
"createdAt": "2023-10",
"count": 3,
}, {
"createdAt": "2023-11",
"count": 2,
}, {
"createdAt": "2023-12",
"count": 1,
}, {
"createdAt": "2024-01",
"count": 1,
},
如有任何帮助,我们将不胜感激!
谢谢!
一种选择是使用日期运算符与
$range
为每个文档创建月份日期列表:
db.collection.aggregate([
{$project: {
months: {
$let: {
vars: {
startMonth: {$dateTrunc: {date: "$createdAt", unit: "month"}},
endMonth: {$dateTrunc: {date: {$ifNull: ["$deletedAt", "$$NOW"]}, unit: "month"}}
},
in: {$map: {
input: {$range: [
0,
{$add: [
{$dateDiff: {startDate: "$$startMonth", endDate: "$$endMonth", unit: "month"}},
1
]}
]},
in: {$dateToString: {
date: {$dateAdd: {
startDate: "$$startMonth", unit: "month", amount: "$$this"
}},
format: "%Y-%m"
}}
}
}
}
}
}},
{$unwind: "$months"},
{$group: {_id: "$months", count: {$sum: 1}}},
{$sort: {_id: 1}},
{$project: {createdAt: "$_id", count: 1, _id: 0}}
])
查看它在 playground 示例中的工作原理