我尝试使用单个查询来显示过去 24 小时和过去 12 小时内的顶级客户。 我们每小时都会在数据库中保存客户的总订单数。 原始数据如下所示,但为了保密我更改了数据:
[
{
"_id": ObjectId("64c8de6e10f1e5f6958033d7"),
"address": "nowhere",
"city": "NY",
"name": "ABD",
"count": NumberInt(19),
"timestamp": ISODate("2023-08-01T05:30:42.956Z")
},
{
"_id": ObjectId("64c8de6e10f1e5f6958033d6"),
"address": "somewhere",
"city": "NY",
"name": "WBE",
"count": NumberInt(4),
"timestamp": ISODate("2023-08-01T05:29:02.956Z")
},
{
"_id": ObjectId("64c8de6e10f1e5f6958033da"),
"address": "somewhere",
"city": "NY",
"name": "WBE",
"count": NumberInt(18),
"timestamp": ISODate("2023-08-01T08:30:42.956Z")
}
...
]
我想要的结果是这样的:
{
last12Hours: [{ name: "WBE", city:"NY", count: "18" }, {name: "ABD", city:"NY", count: "12"}],
last24Hours: [{ name: "WBE", city:"NY", count: "30" }, {name: "ABD", city:"NY", count: "20"}],
}
如果我运行两个查询,将时间戳匹配更改为 12 小时前和 24 小时前,这很简单:
db.collection.aggregate([
{
$match: {
timestamp: {
$gte: ISODate("2023-08-01T03:36:38.059Z")
},
},
},
{
$group: {
_id: "$name",
count: {
$sum: "$count"
},
city: { $first: "$city"}
},
},
{
$sort: {
count: -1
}
},
{
$limit: 5,
},
{
$project: {
_id: 0,
name: "$_id",
city: "$city",
count: 1,
},
},
])
我还尝试了一些与间隔有关的方法,但这对查询来说是一场灾难,并且没有按预期工作。
我很感激提示,我不应该要求任何人来解决它。谢谢!
由于
$facet
不使用索引,您可能希望在管道中尽可能晚地使用它。遵循@YongShun 的另一个选择是使用 $match
在 $group
之前添加 $facet
和 $cond
。这将允许您在这些阶段使用索引,并进入文档较少的$facet
阶段:
db.collection.aggregate([
{$match: {timestamp: {$gte: /* Last 24 hours timestamp */}}},
{$group: {
_id: "$name",
count24: {$sum: "$count"},
count12: {$sum: {$cond: [
{$gte: ["$timestamp",/* Last 12 hours timestamp */]},
"$count",
0
]}},
city: {$first: "$city"}
}},
{$facet: {
last24Hours: [
{$sort: {count24: -1}},
{$limit: 5},
{$project: {_id: 0, name: "$_id", city: 1, count: "$count24"}}
],
last12Hours: [
{$sort: {count12: -1}},
{$limit: 5},
{$match: {count12: {$ne: 0}}},
{$project: {_id: 0, name: "$_id", city: 1, count: "$count12"}}
]
}}
])
查看它在 playground 示例中的工作原理
$facet
阶段在单个阶段内执行多个聚合管道并生成单个文档。
不确定您的
last12HoursTimestamp
和last24HoursTimestamp
是什么,您的查询应如下:
db.collection.aggregate([
{
"$facet": {
"last12Hours": [
{
$match: {
timestamp: {
$gte: /* Last 12 hours timestamp */
}
}
},
{
$group: {
_id: "$name",
count: {
$sum: "$count"
},
city: {
$first: "$city"
}
},
},
{
$sort: {
count: -1
}
},
{
$limit: 5
},
{
$project: {
_id: 0,
name: "$_id",
city: "$city",
count: 1,
}
}
],
"last24Hours": [
{
$match: {
timestamp: {
$gte: /* Last 24 hours timestamp */
}
}
},
{
$group: {
_id: "$name",
count: {
$sum: "$count"
},
city: {
$first: "$city"
}
},
},
{
$sort: {
count: -1
}
},
{
$limit: 5
},
{
$project: {
_id: 0,
name: "$_id",
city: "$city",
count: 1,
}
}
]
}
}
])
奖励:除了传递时间戳之外,您还可以使用 MongoDB 运算符 & 函数来计算过去 12 小时和 24 小时的时间戳。
db.collection.aggregate([
{
$set: {
last12HoursTimestamp: {
"$dateSubtract": {
"startDate": "$$NOW",
"unit": "hour",
"amount": 12
}
},
last24HoursTimestamp: {
"$dateSubtract": {
"startDate": "$$NOW",
"unit": "hour",
"amount": 24
}
},
}
},
{
"$facet": {
"last12Hours": [
{
$match: {
$expr: {
$gte: [
"$timestamp",
"$last12HoursTimestamp"
]
}
}
},
{
$group: {
_id: "$name",
count: {
$sum: "$count"
},
city: {
$first: "$city"
}
},
},
{
$sort: {
count: -1
}
},
{
$limit: 5
},
{
$project: {
_id: 0,
name: "$_id",
city: "$city",
count: 1,
}
}
],
"last24Hours": [
{
$match: {
$expr: {
$gte: [
"$timestamp",
"$last24HoursTimestamp"
]
}
}
},
{
$group: {
_id: "$name",
count: {
$sum: "$count"
},
city: {
$first: "$city"
}
},
},
{
$sort: {
count: -1
}
},
{
$limit: 5
},
{
$project: {
_id: 0,
name: "$_id",
city: "$city",
count: 1
}
}
]
}
}
])