如何在 MongoDB 中获取最近 n 个月的记录(只考虑每个月的最后一条记录)
How to fetch the last n months record(consider only the last entry per month) in MongoDB
我是 MongoDb 的新手。我需要帮助来获取最后 n 个月的记录,每个月可能有多个条目,但查询只需要 return 每个月的最后一个条目。
例如,假设 n 是 3
并且 userId 是 userId1
(这意味着 return 最近 3 个月的记录 userId1
)。
集合中的示例输入:
[
{
"_id": objectId("aaaaaa"),
"userId": "userId1",
"processedAt": "2021-06-01T12:16:49.349Z"
},
{
"_id": objectId("bbbbb"),
"userId": "userId1",
"processedAt": "2021-10-11T12:16:49.349Z"
},
{
"_id": objectId("ccccc"),
"userId": "userId1",
"processedAt": "2021-10-25T12:16:49.349Z"
},
{
"_id": objectId("eeeee"),
"userId": "userId1",
"processedAt": "2021-09-12T12:16:49.349Z"
},
{
"_id": objectId("fffff"),
"userId": "userId1",
"processedAt": "2021-09-28T12:16:49.349Z"
},
{
"_id": objectId("ggggg"),
"userId": "userId1",
"processedAt": "2021-09-23T12:16:49.349Z"
},
{
"_id": objectId("hhhhh"),
"userId": "userId1",
"processedAt": "2021-07-23T12:16:49.349Z"
},
{
"_id": objectId("iiiii"),
"userId": "userId2",
"processedAt": "2021-09-29T12:16:49.349Z"
},
{
"_id": objectId("jjjjj"),
"userId": "userId1",
"processedAt": "2022-01-29T12:16:49.349Z"
},
{
"_id": objectId("kkkkk"),
"userId": "userId1",
"processedAt": "2022-02-29T12:16:49.349Z"
},
]
预期结果:应该return通过userId,限制n个月(仅获取该月最后保存的条目)和processedAt月份的升序:
[{
"_id": objectId("ccccc"),
"userId": "userId1",
"processedAt": "2021-10-25T12:16:49.349Z"
},
{
"_id": objectId("jjjjj"),
"userId": "userId1",
"processedAt": "2022-01-29T12:16:49.349Z"
},
{
"_id": objectId("kkkkk"),
"userId": "userId1",
"processedAt": "2022-02-29T12:16:49.349Z"
}
]
我试过下面的查询,但是 returning 所有记录。我希望查询只需要考虑每月的最后一个条目。我一直在使用 mongojs 驱动 v4.1.2
db.collection(collection_name)
.find({ userId: userId }, { projection: { _id: 0 } })
.sort({ processedAt: -1 })
.limit(n)
.toArray()
从MongoDB5.0开始,
您可以使用 $setWindowFields 为“分区”/“组”(即您的示例中的月份)聚合“排名”,并且只选择排名最高的文档。
排名可以定义为processedAt: -1
,因为您只想保留排名最高的月份的最新记录。
{
"$setWindowFields": {
"partitionBy": {
"$dateToString": {
"date": "$processedAt",
"format": "%Y-%m"
}
},
"sortBy": {
"processedAt": -1
},
"output": {
"rank": {
$rank: {}
}
}
}
}
这里是Mongo playground供您参考。
对于MongoDB 3.6+,
由于示例数据集使用 ISODate 格式,因此可以按最左边的 7 个字符(即 yyyy-MM)对字段进行排序和分组。只保留月份组中的第一个文档应该可以解决问题。
{
$sort: {
processedAt: -1
}
},
{
"$addFields": {
"month": {
"$substrCP": [
"$processedAt",
0,
7
]
}
}
},
{
$group: {
_id: "$month",
last: {
$first: "$$ROOT"
}
}
}
这里是 Mongo playground.
我是 MongoDb 的新手。我需要帮助来获取最后 n 个月的记录,每个月可能有多个条目,但查询只需要 return 每个月的最后一个条目。
例如,假设 n 是 3
并且 userId 是 userId1
(这意味着 return 最近 3 个月的记录 userId1
)。
集合中的示例输入:
[
{
"_id": objectId("aaaaaa"),
"userId": "userId1",
"processedAt": "2021-06-01T12:16:49.349Z"
},
{
"_id": objectId("bbbbb"),
"userId": "userId1",
"processedAt": "2021-10-11T12:16:49.349Z"
},
{
"_id": objectId("ccccc"),
"userId": "userId1",
"processedAt": "2021-10-25T12:16:49.349Z"
},
{
"_id": objectId("eeeee"),
"userId": "userId1",
"processedAt": "2021-09-12T12:16:49.349Z"
},
{
"_id": objectId("fffff"),
"userId": "userId1",
"processedAt": "2021-09-28T12:16:49.349Z"
},
{
"_id": objectId("ggggg"),
"userId": "userId1",
"processedAt": "2021-09-23T12:16:49.349Z"
},
{
"_id": objectId("hhhhh"),
"userId": "userId1",
"processedAt": "2021-07-23T12:16:49.349Z"
},
{
"_id": objectId("iiiii"),
"userId": "userId2",
"processedAt": "2021-09-29T12:16:49.349Z"
},
{
"_id": objectId("jjjjj"),
"userId": "userId1",
"processedAt": "2022-01-29T12:16:49.349Z"
},
{
"_id": objectId("kkkkk"),
"userId": "userId1",
"processedAt": "2022-02-29T12:16:49.349Z"
},
]
预期结果:应该return通过userId,限制n个月(仅获取该月最后保存的条目)和processedAt月份的升序:
[{
"_id": objectId("ccccc"),
"userId": "userId1",
"processedAt": "2021-10-25T12:16:49.349Z"
},
{
"_id": objectId("jjjjj"),
"userId": "userId1",
"processedAt": "2022-01-29T12:16:49.349Z"
},
{
"_id": objectId("kkkkk"),
"userId": "userId1",
"processedAt": "2022-02-29T12:16:49.349Z"
}
]
我试过下面的查询,但是 returning 所有记录。我希望查询只需要考虑每月的最后一个条目。我一直在使用 mongojs 驱动 v4.1.2
db.collection(collection_name)
.find({ userId: userId }, { projection: { _id: 0 } })
.sort({ processedAt: -1 })
.limit(n)
.toArray()
从MongoDB5.0开始,
您可以使用 $setWindowFields 为“分区”/“组”(即您的示例中的月份)聚合“排名”,并且只选择排名最高的文档。
排名可以定义为processedAt: -1
,因为您只想保留排名最高的月份的最新记录。
{
"$setWindowFields": {
"partitionBy": {
"$dateToString": {
"date": "$processedAt",
"format": "%Y-%m"
}
},
"sortBy": {
"processedAt": -1
},
"output": {
"rank": {
$rank: {}
}
}
}
}
这里是Mongo playground供您参考。
对于MongoDB 3.6+,
由于示例数据集使用 ISODate 格式,因此可以按最左边的 7 个字符(即 yyyy-MM)对字段进行排序和分组。只保留月份组中的第一个文档应该可以解决问题。
{
$sort: {
processedAt: -1
}
},
{
"$addFields": {
"month": {
"$substrCP": [
"$processedAt",
0,
7
]
}
}
},
{
$group: {
_id: "$month",
last: {
$first: "$$ROOT"
}
}
}
这里是 Mongo playground.