MongoDB聚合根据时间进行多重分组

问题描述 投票:0回答:2

我尝试使用单个查询来显示过去 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,
    },
  },
])

我还尝试了一些与间隔有关的方法,但这对查询来说是一场灾难,并且没有按预期工作。

我很感激提示,我不应该要求任何人来解决它。谢谢!

mongodb mongodb-query aggregation-framework
2个回答
2
投票

由于

$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 示例中的工作原理


2
投票

对于您的场景,您需要

$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,
            
          }
        }
      ]
    }
  }
])

演示@Mongo Playground

奖励:除了传递时间戳之外,您还可以使用 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
          }
        }
      ]
    }
  }
])
© www.soinside.com 2019 - 2024. All rights reserved.