MongoDB 每组 select 具有最大值的记录
MongoDB For each group select the records with the max value
在 MongoDB 中,我试图将集合过滤为仅包含各自组中包含最新日期的文档。
在传统的 SQL 中,我会这样做:
Select *
From table a
Join (Select my_group, max(date) as max_date
From table group by my_group) b
ON a.my_group = b.my_group AND
a.date = b.max_date
带有以下示例集合:
[
{
"_id": "123",
"item1": "group 1",
"item2": "abc",
"item3": "abc",
"date": "2022-01-01"
},
{
"_id": "234",
"item1": "group 1",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
},
{
"_id": "345",
"item1": "group 1",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
},
{
"_id": "789",
"item1": "group 2",
"item2": "abc",
"item3": "abc",
"date": "2022-01-01"
},
{
"_id": "678",
"item1": "group 2",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
},
{
"_id": "456",
"item1": "group 2",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
}
]
预期输出为:
[
{
"_id": "234",
"date": "2022-01-02",
"item1": "group 1",
"item2": "abc",
"item3": "abc"
},
{
"_id": "345",
"date": "2022-01-02",
"item1": "group 1",
"item2": "abc",
"item3": "abc"
},
{
"_id": "678",
"date": "2022-01-02",
"item1": "group 2",
"item2": "abc",
"item3": "abc"
},
{
"_id": "456",
"date": "2022-01-02",
"item1": "group 2",
"item2": "abc",
"item3": "abc"
}
]
我目前最好的尝试是:
db.collection.aggregate([
{
$group: {
"_id": "$item1",
"max_date": {
$max: "$date"
},
"records": {
$push: "$$ROOT"
}
}
},
{
"$project": {
items: {
"$filter": {
"input": "$records",
"as": "records",
"cond": {
$eq: [
"$$records.date",
"$max_date"
]
}
}
}
}
},
{
$replaceRoot: {
newRoot: {
results: "$items"
}
}
}
])
不幸的是,returns 结果按组划分。我尝试了其他帖子建议的一些替代方案并遇到了类似的问题,例如:
- MongoDB get rows where max value grouped
这是一个包含查询和示例数据的 playground example。
你离答案很近了。
最后两个阶段:
$unwind
- 将items
数组字段解构为多个文档。
$replaceWith
- 用 items
文档替换输出文档。
db.collection.aggregate([
{
$group: {
"_id": "$item1",
"max_date": {
$max: "$date"
},
"records": {
$push: "$$ROOT"
}
}
},
{
"$project": {
items: {
"$filter": {
"input": "$records",
"as": "records",
"cond": {
$eq: [
"$$records.date",
"$max_date"
]
}
}
}
}
},
{
$unwind: "$items"
},
{
$replaceWith: "$items"
}
])
奖金
虽然上面的查询更好,但也想分享类似于 SQL 实现的 MongoDB 查询。
$group
- 按 item1
分组并获得 date
. 的最大值
$lookup
- 自己加入 item1
和 date
的集合。和returnsitems
数组字段。
$match
- 使用 items
而非空数组过滤文档。
$unwind
- 将 items
数组解构为多个文档。
$replaceWith
- 将输出文档替换为 items
文档。
db.collection.aggregate([
{
$group: {
"_id": "$item1",
"max_date": {
$max: "$date"
}
}
},
{
$lookup: {
from: "collection",
let: {
item1: "$_id",
max_date: "$max_date"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$item1",
"$$item1"
]
},
{
$eq: [
"$date",
"$$max_date"
]
}
]
}
}
}
],
as: "items"
}
},
{
$match: {
items: {
$ne: []
}
}
},
{
$unwind: "$items"
},
{
$replaceWith: "$items"
}
])
在 MongoDB 中,我试图将集合过滤为仅包含各自组中包含最新日期的文档。
在传统的 SQL 中,我会这样做:
Select *
From table a
Join (Select my_group, max(date) as max_date
From table group by my_group) b
ON a.my_group = b.my_group AND
a.date = b.max_date
带有以下示例集合:
[
{
"_id": "123",
"item1": "group 1",
"item2": "abc",
"item3": "abc",
"date": "2022-01-01"
},
{
"_id": "234",
"item1": "group 1",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
},
{
"_id": "345",
"item1": "group 1",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
},
{
"_id": "789",
"item1": "group 2",
"item2": "abc",
"item3": "abc",
"date": "2022-01-01"
},
{
"_id": "678",
"item1": "group 2",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
},
{
"_id": "456",
"item1": "group 2",
"item2": "abc",
"item3": "abc",
"date": "2022-01-02"
}
]
预期输出为:
[
{
"_id": "234",
"date": "2022-01-02",
"item1": "group 1",
"item2": "abc",
"item3": "abc"
},
{
"_id": "345",
"date": "2022-01-02",
"item1": "group 1",
"item2": "abc",
"item3": "abc"
},
{
"_id": "678",
"date": "2022-01-02",
"item1": "group 2",
"item2": "abc",
"item3": "abc"
},
{
"_id": "456",
"date": "2022-01-02",
"item1": "group 2",
"item2": "abc",
"item3": "abc"
}
]
我目前最好的尝试是:
db.collection.aggregate([
{
$group: {
"_id": "$item1",
"max_date": {
$max: "$date"
},
"records": {
$push: "$$ROOT"
}
}
},
{
"$project": {
items: {
"$filter": {
"input": "$records",
"as": "records",
"cond": {
$eq: [
"$$records.date",
"$max_date"
]
}
}
}
}
},
{
$replaceRoot: {
newRoot: {
results: "$items"
}
}
}
])
不幸的是,returns 结果按组划分。我尝试了其他帖子建议的一些替代方案并遇到了类似的问题,例如:
- MongoDB get rows where max value grouped
这是一个包含查询和示例数据的 playground example。
你离答案很近了。
最后两个阶段:
$unwind
- 将items
数组字段解构为多个文档。$replaceWith
- 用items
文档替换输出文档。
db.collection.aggregate([
{
$group: {
"_id": "$item1",
"max_date": {
$max: "$date"
},
"records": {
$push: "$$ROOT"
}
}
},
{
"$project": {
items: {
"$filter": {
"input": "$records",
"as": "records",
"cond": {
$eq: [
"$$records.date",
"$max_date"
]
}
}
}
}
},
{
$unwind: "$items"
},
{
$replaceWith: "$items"
}
])
奖金
虽然上面的查询更好,但也想分享类似于 SQL 实现的 MongoDB 查询。
$group
- 按item1
分组并获得date
. 的最大值
$lookup
- 自己加入item1
和date
的集合。和returnsitems
数组字段。$match
- 使用items
而非空数组过滤文档。$unwind
- 将items
数组解构为多个文档。$replaceWith
- 将输出文档替换为items
文档。
db.collection.aggregate([
{
$group: {
"_id": "$item1",
"max_date": {
$max: "$date"
}
}
},
{
$lookup: {
from: "collection",
let: {
item1: "$_id",
max_date: "$max_date"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$item1",
"$$item1"
]
},
{
$eq: [
"$date",
"$$max_date"
]
}
]
}
}
}
],
as: "items"
}
},
{
$match: {
items: {
$ne: []
}
}
},
{
$unwind: "$items"
},
{
$replaceWith: "$items"
}
])