当前位置:首页 > 文章列表 > 文章 > php教程 > Laravel通知合并去重方法解析

Laravel通知合并去重方法解析

2025-12-12 23:36:36 0浏览 收藏
推广推荐
免费电影APP ➜
支持 PC / 移动端,安全直达

golang学习网今天将给大家带来《Laravel通知合并去重技巧解析》,感兴趣的朋友请继续看下去吧!以下内容将会涉及到等等知识点,如果你是正在学习文章或者已经是大佬级别了,都非常欢迎也希望大家都能给我建议评论哈~希望能帮助到大家!

Laravel数据库通知的智能管理:实现通知合并与去重

在Laravel应用中,当短时间内有大量事件触发通知时,用户可能会收到过多的重复或相似通知,导致体验不佳。本文将详细介绍如何通过优化Laravel的数据库通知机制,实现在特定时间窗口内合并或更新现有通知,而非创建新的通知,从而有效减少通知数量,提升用户体验。

引言:优化通知体验的必要性

在现代Web应用中,通知是与用户互动的重要手段。然而,如果通知系统设计不当,例如在短时间内针对同一事件或同一类事件发送大量独立通知,用户体验将大打折扣,可能导致“通知疲劳”,甚至让用户选择关闭通知功能。为了解决这一问题,我们需要一种机制,能够在特定条件下对通知进行“去重”或“合并”,例如,在30分钟内,将关于同一主题的多个通知合并为一个,只更新其计数或内容。

Laravel数据库通知基础

Laravel的通知系统提供了一个便捷的方式来向用户发送各类通知。对于数据库通知,我们通常会在通知类的 toDatabase 方法中定义要存储到 notifications 表中的数据。当 Notification::send() 方法被调用时,Laravel会调用相应渠道(如 toDatabase)的方法,并将其返回的数据存储起来。

toDatabase 方法的典型结构如下:

public function toDatabase($notifiable): array
{
    return [
        'content' => '这是一条新通知',
        'type' => 'post_created',
        'post_id' => $this->post->id,
    ];
}

Laravel会将这个返回的数组存储到 notifications 表的 data 字段中。

策略:合并或更新现有通知

我们的核心策略是:当一个事件触发通知时,首先检查在预设的时间窗口(例如30分钟)内,是否已经存在一个针对相同主题的通知。

  • 如果存在,则更新这个现有通知的 data 字段(例如,增加一个计数器,或修改通知内容),并阻止创建新的通知。
  • 如果不存在,则创建一条全新的通知。

实现通知合并逻辑

为了实现上述策略,我们需要修改通知类中的 toDatabase 方法。原始的问题代码尝试在找到现有通知后进行更新,但最终仍然会执行方法末尾的 return [] 语句,导致即使更新了旧通知,也会创建一条新通知。

关键在于:当成功更新现有通知后,必须阻止 toDatabase 方法继续返回一个非空的数组,因为任何非空数组都会被Laravel视为一条新的通知记录来存储。 返回一个空数组 [] 或 null 是阻止新通知创建的有效方式。

下面是优化后的 toDatabase 方法示例:

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\DatabaseMessage;
use App\Models\Search; // 假设您的Search模型

class PostMatchedSearchNotification extends Notification
{
    use Queueable;

    protected Search $search;
    protected string $postTitle; // 假设通知中需要展示的帖子标题

    /**
     * 创建一个新的通知实例。
     *
     * @param Search $search 触发通知的搜索条件
     * @param string $postTitle 匹配到的帖子标题
     * @return void
     */
    public function __construct(Search $search, string $postTitle = '新帖子')
    {
        $this->search = $search;
        $this->postTitle = $postTitle;
    }

    /**
     * 获取通知的交付渠道。
     *
     * @param mixed $notifiable
     * @return array
     */
    public function via($notifiable): array
    {
        return ['database'];
    }

    /**
     * 将通知转换为数据库存储的数组。
     *
     * @param mixed $notifiable
     * @return array
     */
    public function toDatabase($notifiable): array
    {
        $timeWindowMinutes = 30; // 定义时间窗口:30分钟
        $searchIdentifier = $this->search->id; // 用于识别相关通知的唯一标识

        // 尝试查找在指定时间窗口内,针对当前搜索条件已存在的通知
        $existingNotification = $notifiable->notifications()
            ->where('data->search_id', $searchIdentifier) // 使用 data->search_id 进行查询
            ->where('created_at', '>=', now()->subMinutes($timeWindowMinutes))
            ->first();

        if ($existingNotification) {
            // 如果找到了现有通知,则更新它
            $currentCount = $existingNotification->data['count'] ?? 0;
            $newCount = $currentCount + 1;

            $existingNotification->update([
                'data' => array_merge($existingNotification->data, [
                    'content' => [
                        'en' => "{$newCount} new posts matched with your saved search '{$this->search->title}' have been posted. Click to view more.",
                        'zh' => "您的保存搜索 '{$this->search->title}' 匹配到 {$newCount} 篇新帖子。点击查看更多。",
                    ],
                    'count' => $newCount,
                    // 可以更新其他相关数据,例如最后更新时间
                    'last_updated_at' => now()->toDateTimeString(),
                    // 确保 search_id 和 parameters 等关键标识符仍然存在
                    'search_id' => $searchIdentifier,
                    'parameters' => $this->search->parameters,
                ])
            ]);

            // 关键:返回一个空数组,阻止Laravel创建新的通知记录
            return [];
        }

        // 如果在时间窗口内没有找到现有通知,则创建一条新的通知
        return [
            'content' => [
                'en' => "1 new post matched with your saved search '{$this->search->title}' has been posted. Click to view more.",
                'zh' => "您的保存搜索 '{$this->search->title}' 匹配到 1 篇新帖子。点击查看更多。",
            ],
            'count' => 1,
            'search_id' => $searchIdentifier, // 用于后续查询的标识符
            'parameters' => $this->search->parameters,
            'first_matched_post_title' => $this->postTitle, // 首次匹配到的帖子标题
            'created_at' => now()->toDateTimeString(), // 记录创建时间
        ];
    }
}

代码解析:

  1. $timeWindowMinutes = 30;: 定义了通知合并的时间窗口。
  2. $searchIdentifier = $this->search->id;: 定义了一个唯一标识符,用于识别属于同一组的通知。这里使用了 search_id,但在实际应用中,您可以根据业务逻辑选择任何合适的字段(例如 product_id, category_id 等)。
  3. $notifiable->notifications()->where('data->search_id', $searchIdentifier)->where('created_at', '>=', now()->subMinutes($timeWindowMinutes))->first();:
    • $notifiable->notifications(): 获取当前用户(或任何可通知实体)的所有通知。
    • where('data->search_id', $searchIdentifier): 使用JSON列查询语法,查找 data 字段中 search_id 匹配的通知。
    • where('created_at', '>=', now()->subMinutes($timeWindowMinutes)): 限制查询范围,只查找在过去30分钟内创建的通知。这里使用 created_at 是为了确保我们是在一个“新鲜”的时间窗口内进行合并,而不是无限期地更新一个非常老的通知。
    • first(): 获取符合条件的第一条通知。
  4. if ($existingNotification) 块:
    • 如果找到了现有通知,我们从中获取当前的计数 ($existingNotification->data['count'] ?? 0) 并递增。
    • $existingNotification->update(['data' => array_merge(...)]): 使用 array_merge 来合并旧的 data 数据和新的更新数据,这样可以保留 data 字段中其他未修改的信息。更新通知的 data 字段和 updated_at 时间戳。
    • return [];: 这是关键!当通知被成功更新后,返回一个空数组。这会告诉Laravel的通知系统,不需要再存储一个新的通知记录,从而达到了合并通知的目的。
  5. else 块(即 if 块之后的 return 语句):
    • 如果未找到现有通知(即 $existingNotification 为 null),则意味着这是一个全新的通知事件,此时正常返回一个包含所有通知内容的数组,Laravel会将其作为一条新记录存储。

进阶考量与最佳实践

  1. created_at 与 updated_at 的选择:

    • 在查询现有通知时,使用 created_at 配合时间窗口 (now()->subMinutes(30)) 是一个常见的做法,它确保我们总是在一个相对较新的通知序列中进行合并。
    • notifications 表自身的 updated_at 字段会在每次更新 data 字段时自动更新,这可以用来追踪通知的活跃度。
    • 您也可以在 data 字段内部维护一个 last_updated_at 字段,以更精细地控制何时“重置”通知周期,即如果距离 last_updated_at 超过30分钟,就创建新通知,否则更新。这与答案中提到的 Last_send 概念类似。
  2. data 字段的设计:

    • 保持 data 字段的结构清晰且一致至关重要。例如,始终包含一个 search_id 或 type 字段,以便于查询和识别相关通知。
    • 对于多语言内容,可以将 content 字段设计为包含不同语言版本的数组,如示例中的 ['en' => '...', 'zh' => '...']。
  3. 性能考量:

    • 对于拥有大量用户的系统,频繁查询 notifications 表可能会带来性能压力。确保 notifications 表上的 notifiable_id, notifiable_type, created_at 字段以及 data 字段中的常用查询键(例如 data->search_id)有合适的索引。
    • 如果通知量特别巨大,可以考虑将通知合并逻辑放在队列中处理,以避免阻塞主请求。
  4. 用户体验:

    • 在前端展示时,需要考虑如何清晰地呈现合并后的通知,例如显示“5篇新帖子”或“X条新消息”等聚合信息。
    • 点击合并通知后,应引导用户到一个聚合页面,展示所有相关的最新内容。
  5. 其他通知渠道:

    • 此方法主要针对数据库通知。如果您的应用还使用了邮件、短信或其他实时通知渠道,则需要为这些渠道单独设计去重或合并逻辑,因为它们的发送机制和存储方式不同。

总结

通过在Laravel通知类的 toDatabase 方法中引入条件判断和早期返回机制,我们可以有效地实现数据库通知的智能合并与去重。这不仅能够显著减少用户收到的通知数量,避免“通知疲劳”,还能提升整体的用户体验。合理设计 data 字段结构,并结合索引优化,可以确保此方案在不同规模的应用中都能高效运行。

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于文章的相关知识,也可关注golang学习网公众号。

Python文件读取常用strip与split方法详解Python文件读取常用strip与split方法详解
上一篇
Python文件读取常用strip与split方法详解
Go启动子进程控制用户组与I/O方法
下一篇
Go启动子进程控制用户组与I/O方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ChatExcel酷表:告别Excel难题,北大团队AI助手助您轻松处理数据
    ChatExcel酷表
    ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
    3280次使用
  • Any绘本:开源免费AI绘本创作工具深度解析
    Any绘本
    探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
    3492次使用
  • 可赞AI:AI驱动办公可视化智能工具,一键高效生成文档图表脑图
    可赞AI
    可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
    3522次使用
  • 星月写作:AI网文创作神器,助力爆款小说速成
    星月写作
    星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
    4631次使用
  • MagicLight.ai:叙事驱动AI动画视频创作平台 | 高效生成专业级故事动画
    MagicLight
    MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
    3901次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码