导读:本期聚焦于小伙伴创作的《Laravel MongoDB 中如何实现按小时分组并动态聚合各分类价格总和》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Laravel MongoDB 中如何实现按小时分组并动态聚合各分类价格总和》有用,将其分享出去将是对创作者最好的鼓励。

在Laravel项目结合MongoDB的使用场景中,按小时分组并动态聚合各分类价格总和是常见的数据统计需求,比如统计每小时不同商品分类的订单总金额,这类需求可以通过MongoDB的聚合管道配合Laravel的MongoDB查询扩展来实现。

Laravel MongoDB 中如何实现按小时分组并动态聚合各分类价格总和

核心实现思路

实现该需求主要分为三个步骤:首先提取数据中的小时维度,然后按照小时和分类字段进行分组,最后动态计算不同分类的价格总和。MongoDB的聚合管道提供了$dateToString操作符用于提取时间中的小时部分,$group操作符用于分组聚合,结合Laravel的MongoDB查询构造器可以很方便地组装这些聚合操作。

基础数据准备

假设我们的MongoDB集合名为orders,每条订单数据包含以下字段:

  • created_at:订单创建时间,类型为MongoDB的ISODate
  • category:订单所属分类,值为字符串,比如电子产品、服装等
  • price:订单价格,类型为数值

Laravel中聚合管道实现

首先需要在Laravel项目中安装MongoDB的扩展包,确保可以正常操作MongoDB数据库。接下来编写聚合查询代码:

<?php

namespace AppServices;

use MongoDBClient;
use CarbonCarbon;

class OrderStatService
{
    protected $mongoClient;

    public function __construct()
    {
        // 初始化MongoDB客户端,这里使用默认的本地连接配置
        $this->mongoClient = new Client('mongodb://127.0.0.1:27017');
    }

    /**
     * 按小时分组动态聚合各分类价格总和
     * @param string $startTime 统计开始时间
     * @param string $endTime 统计结束时间
     * @param array $categories 需要统计的分类列表,为空则统计所有分类
     * @return array
     */
    public function hourlyCategoryPriceSum($startTime, $endTime, $categories = [])
    {
        $database = $this->mongoClient->selectDatabase('test_db');
        $collection = $database->selectCollection('orders');

        // 组装聚合管道
        $pipeline = [];

        // 第一步:时间范围过滤
        $matchCondition = [
            'created_at' => [
                '$gte' => new MongoDBBSONUTCDateTime(Carbon::parse($startTime)->timestamp * 1000),
                '$lte' => new MongoDBBSONUTCDateTime(Carbon::parse($endTime)->timestamp * 1000)
            ]
        ];
        // 如果指定了分类,添加分类过滤条件
        if (!empty($categories)) {
            $matchCondition['category'] = ['$in' => $categories];
        }
        $pipeline[] = ['$match' => $matchCondition];

        // 第二步:提取小时维度,添加小时字段
        $pipeline[] = [
            '$addFields' => [
                'hour' => [
                    '$dateToString' => [
                        'format' => '%H',
                        'date' => '$created_at',
                        'timezone' => 'Asia/Shanghai' // 设置为本地时区
                    ]
                ]
            ]
        ];

        // 第三步:按小时和分类分组,聚合价格总和
        $pipeline[] = [
            '$group' => [
                '_id' => [
                    'hour' => '$hour',
                    'category' => '$category'
                ],
                'total_price' => ['$sum' => '$price'],
                'order_count' => ['$sum' => 1]
            ]
        ];

        // 第四步:格式化输出结果
        $pipeline[] = [
            '$project' => [
                '_id' => 0,
                'hour' => '$_id.hour',
                'category' => '$_id.category',
                'total_price' => 1,
                'order_count' => 1
            ]
        ];

        // 执行聚合查询
        $result = $collection->aggregate($pipeline)->toArray();

        return $result;
    }
}

代码解析

上述代码的核心逻辑如下:

  • $match阶段:先过滤出指定时间范围和分类的订单数据,减少后续聚合的数据量,提升查询效率。
  • $addFields阶段:使用$dateToString操作符从created_at字段中提取小时部分,生成新的hour字段,格式为两位小时数,比如08、14等。
  • $group阶段:按照hourcategory两个字段组合分组,使用$sum操作符计算每个分组的价格总和,同时统计每个分组的订单数量。
  • $project阶段:调整输出结果的字段格式,去掉默认的_id字段,将分组条件字段提取为独立字段,方便后续使用。

动态分类处理说明

上述代码中的$categories参数支持动态传入需要统计的分类列表,如果传入空数组则会统计所有存在的分类。如果业务需要动态适配不同的分类字段,比如有时候按category统计,有时候按sub_category统计,只需要将分组字段改为动态参数即可:

// 动态分组字段示例,将分类字段作为参数传入
public function hourlyDynamicGroupPriceSum($startTime, $endTime, $groupField = 'category')
{
    $database = $this->mongoClient->selectDatabase('test_db');
    $collection = $database->selectCollection('orders');

    $pipeline = [];

    // 时间过滤
    $pipeline[] = [
        '$match' => [
            'created_at' => [
                '$gte' => new MongoDBBSONUTCDateTime(Carbon::parse($startTime)->timestamp * 1000),
                '$lte' => new MongoDBBSONUTCDateTime(Carbon::parse($endTime)->timestamp * 1000)
            ]
        ]
    ];

    // 提取小时字段
    $pipeline[] = [
        '$addFields' => [
            'hour' => [
                '$dateToString' => [
                    'format' => '%H',
                    'date' => '$created_at',
                    'timezone' => 'Asia/Shanghai'
                ]
            ]
        ]
    ];

    // 动态分组,使用传入的字段名作为分组条件
    $pipeline[] = [
        '$group' => [
            '_id' => [
                'hour' => '$hour',
                'group_field' => '$' . $groupField // 动态引用字段
            ],
            'total_price' => ['$sum' => '$price']
        ]
    ];

    // 格式化输出
    $pipeline[] = [
        '$project' => [
            '_id' => 0,
            'hour' => '$_id.hour',
            'group_value' => '$_id.group_field',
            'total_price' => 1
        ]
    ];

    return $collection->aggregate($pipeline)->toArray();
}

结果示例

执行上述查询后,返回的结果格式如下:

[
    {
        "hour": "08",
        "category": "电子产品",
        "total_price": 15680.5,
        "order_count": 12
    },
    {
        "hour": "08",
        "category": "服装",
        "total_price": 8920.0,
        "order_count": 8
    },
    {
        "hour": "09",
        "category": "电子产品",
        "total_price": 23450.0,
        "order_count": 18
    }
]

如果需要将结果按小时维度整理,把同一小时的不同分类数据合并到一个条目中,可以在获取到聚合结果后做二次处理:

// 整理结果为按小时分组的格式
public function formatResultByHour($rawResult)
{
    $formatted = [];
    foreach ($rawResult as $item) {
        $hour = $item['hour'];
        if (!isset($formatted[$hour])) {
            $formatted[$hour] = [
                'hour' => $hour,
                'category_sum' => []
            ];
        }
        $formatted[$hour]['category_sum'][$item['category']] = [
            'total_price' => $item['total_price'],
            'order_count' => $item['order_count']
        ];
    }
    return array_values($formatted);
}

注意事项

  • MongoDB的时间字段如果是字符串类型,需要先使用$toDate操作符转换为ISODate类型再进行时间提取操作。
  • 时区设置需要根据项目实际使用的时区调整,避免小时提取出现偏差。
  • 如果数据量较大,建议在created_atcategory字段上创建复合索引,提升聚合查询的性能。
  • 动态传入分组字段时,需要做好参数校验,避免传入不存在的字段导致查询报错。

LaravelMongoDB按小时分组动态聚合分类价格总和修改时间:2026-07-03 17:39:39

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。