
本文旨在提供一种优化 Laravel 数据库通知的方法,以避免在短时间内发送大量重复或相似的通知。通过实现基于时间窗口的通知聚合策略,可以在特定时间段内将多个相关事件合并为一个通知,并自动更新其计数,从而提升用户体验并减少数据库负担。
在构建现代 Web 应用程序时,通知功能是用户体验的关键组成部分。然而,当系统在短时间内触发大量相似的通知时(例如,多个新帖子匹配了用户的保存搜索),用户可能会感到信息过载。为了解决这一问题,我们可以采用一种策略:在指定的时间窗口内,将相关的通知进行聚合,而不是为每个事件都创建一条新的通知。这种聚合方式通常表现为更新现有通知的计数和内容。
该策略的核心思想是:当一个新事件触发通知时,首先检查在最近一个预定义的时间窗口内(例如30分钟),是否存在与此事件高度相关的未读通知。
通过这种方式,用户只会看到一条不断更新的通知,而不是一连串独立的通知,直到超过时间窗口或用户阅读了该通知。
Laravel 的通知系统通过 toDatabase 方法定义了通知如何存储到数据库。为了实现通知聚合,我们需要在该方法中加入条件逻辑。关键在于,当成功更新现有通知时,toDatabase 方法应返回 null 或 false,以阻止 Laravel 默认的通知创建行为。
以下是修改后的 toDatabase 方法示例,它实现了基于搜索 ID 和时间窗口的通知聚合:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\DatabaseMessage; // 引入 DatabaseMessage 可选,直接返回数组也可
class PostMatchedSearch extends Notification implements ShouldQueue // 推荐使用队列
{
use Queueable;
protected $search;
// 可以在构造函数中传入更多上下文信息,例如触发通知的 Post 对象
protected $post;
/**
* 创建一个新的通知实例。
*
* @param \App\Models\Search $search
* @param \App\Models\Post|null $post
* @return void
*/
public function __construct($search, $post = null)
{
$this->search = $search;
$this->post = $post;
}
/**
* 获取通知的投递渠道。
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable): array
{
return ['database'];
}
/**
* 获取通知的数据库表示。
*
* @param mixed $notifiable
* @return array|null
*/
public function toDatabase($notifiable): ?array
{
// 定义通知聚合的时间窗口(例如30分钟)
$timeWindowMinutes = 30;
// 构造当前通知的数据,其中包含用于识别聚合的键(如 'search_id')
$currentNotificationData = [
'search_id' => $this->search->id,
'title' => $this->search->title,
'parameters' => $this->search->parameters,
// 如果需要,可以在这里记录触发当前通知的最新帖子ID
'latest_post_id' => $this->post ? $this->post->id : null,
];
// 尝试查找在指定时间窗口内,与当前搜索相关的未读通知
// 1. where('type', self::class) 确保只聚合同类型的通知
// 2. where('read_at', null) 确保只聚合用户尚未阅读的通知
// 3. where('data->search_id', $this->search->id) 通过JSON字段精确匹配搜索ID
// 4. where('created_at', '>=', now()->subMinutes($timeWindowMinutes)) 定义时间窗口
$existingNotification = $notifiable->notifications()
->where('type', self::class)
->where('read_at', null)
->where('data->search_id', $this->search->id)
->where('created_at', '>=', now()->subMinutes($timeWindowMinutes))
->first();
if ($existingNotification) {
// 如果找到现有通知,更新其计数和内容
$currentCount = $existingNotification->data['count'] ?? 1;
$newCount = $currentCount + 1;
// 更新现有通知的数据
$existingNotification->update([
'data' => array_merge($existingNotification->data, [
'count' => $newCount,
'content' => [
'en' => "{$newCount} new posts matched with your saved search {$this->search->title} have been posted. Click here to view more.",
// 可以添加一个时间戳,表示最后更新时间
'last_updated' => now()->toDateTimeString(),
],
// 更新最新的帖子ID
'latest_post_id' => $this->post ? $this->post->id : null,
]),
'updated_at' => now(), // 手动更新 updated_at 字段
]);
// 返回 null 阻止创建新的通知记录
return null;
}
// 如果没有找到现有通知,则创建新的通知
return [
'content' => [
'en' => "1 new post matched with your saved search {$this->search->title} has been posted. Click here to view more.",
],
'count' => 1,
// 确保这里返回的数据结构与查询时使用的键(如 'search_id')一致
'search_id' => $this->search->id,
'parameters' => $this->search->parameters,
'latest_post_id' => $this->post ? $this->post->id : null,
];
}
}通过在 toDatabase 方法中引入条件逻辑并巧妙利用 return null,我们能够有效地实现 Laravel 数据库通知的聚合与计数更新。这种策略不仅减少了通知的泛滥,提升了用户体验,也降低了数据库的存储压力。在设计通知系统时,灵活运用这种模式,可以根据实际业务场景创建更加智能和用户友好的通知机制。
以上就是Laravel 数据库通知聚合与计数更新策略的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号