perf: 优化会话数据结构

This commit is contained in:
kuaifan 2024-03-17 15:18:51 +09:00
parent 47c9b2e1b0
commit 006fc43498
8 changed files with 134 additions and 38 deletions

View File

@ -108,12 +108,12 @@ class DialogController extends AbstractController
return Base::retError('请输入搜索关键词');
}
// 搜索会话
$dialogs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
$dialogs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->where('web_socket_dialogs.name', 'LIKE', "%{$key}%")
->where('u.userid', $user->userid)
->orderByDesc('u.top_at')
->orderByDesc('web_socket_dialogs.last_at')
->orderByDesc('u.last_at')
->take(20)
->get();
$dialogs->transform(function (WebSocketDialog $item) use ($user) {
@ -145,7 +145,7 @@ class DialogController extends AbstractController
}
// 搜索消息会话
if (count($list) < 20) {
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
->where('u.userid', $user->userid)
@ -178,7 +178,7 @@ class DialogController extends AbstractController
{
$user = User::auth();
// 搜索会话
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
->where('u.userid', $user->userid)
@ -213,7 +213,7 @@ class DialogController extends AbstractController
//
$dialog_id = intval(Request::input('dialog_id'));
//
$item = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
$item = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->where('web_socket_dialogs.id', $dialog_id)
->where('u.userid', $user->userid)

View File

@ -20,9 +20,9 @@ use Illuminate\Support\Facades\DB;
* @property string|null $group_type 聊天室类型
* @property string|null $name 对话名称
* @property string $avatar 头像(群)
* @property string|null $last_at 最后消息时间
* @property int|null $owner_id 群主用户ID
* @property int|null $link_id 关联id
* @property int|null $top_userid 置顶的用户ID
* @property int|null $top_msg_id 置顶的消息ID
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
@ -38,11 +38,11 @@ use Illuminate\Support\Facades\DB;
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereGroupType($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereLastAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereLinkId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereOwnerId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereTopMsgId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereTopUserid($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereType($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog withTrashed()
@ -81,7 +81,7 @@ class WebSocketDialog extends AbstractModel
*/
public static function getDialogList($userid, $updated = "", $deleted = "")
{
$builder = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
$builder = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->where('u.userid', $userid);
if ($updated) {
@ -89,7 +89,7 @@ class WebSocketDialog extends AbstractModel
}
$list = $builder
->orderByDesc('u.top_at')
->orderByDesc('web_socket_dialogs.last_at')
->orderByDesc('u.last_at')
->paginate(Base::getPaginate(100, 50));
$list->transform(function (WebSocketDialog $item) use ($userid) {
return $item->formatData($userid);
@ -112,15 +112,15 @@ class WebSocketDialog extends AbstractModel
public static function getDialogUnread($userid, $beforeAt, $take = 20)
{
DB::statement("SET SQL_MODE=''");
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->join('web_socket_dialog_msg_reads as r', 'web_socket_dialogs.id', '=', 'r.dialog_id')
->where('u.userid', $userid)
->where('r.userid', $userid)
->where('r.silence', 0)
->where('r.read_at')
->where('web_socket_dialogs.last_at', '>', $beforeAt)
->groupBy('web_socket_dialogs.id')
->where('u.last_at', '>', $beforeAt)
->groupBy('u.dialog_id')
->take(min(100, $take))
->get();
$list->transform(function (WebSocketDialog $item) use ($userid) {
@ -149,6 +149,7 @@ class WebSocketDialog extends AbstractModel
$time = Carbon::parse($this->user_at ?? $dialogUserFun('updated_at'));
$this->hide = $this->hide ?? $dialogUserFun('hide');
$this->top_at = $this->top_at ?? $dialogUserFun('top_at');
$this->last_at = $this->last_at ?? $dialogUserFun('last_at');
$this->user_at = $time->toDateTimeString('millisecond');
$this->user_ms = $time->valueOf();
//
@ -552,20 +553,6 @@ class WebSocketDialog extends AbstractModel
Task::deliver($task);
}
/**
* 更新对话最后消息时间
* @return WebSocketDialogMsg|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|\Illuminate\Database\Query\Builder|object|null
*/
public function updateMsgLastAt()
{
$lastMsg = WebSocketDialogMsg::whereDialogId($this->id)->orderByDesc('id')->first();
if ($lastMsg) {
$this->last_at = $lastMsg->created_at;
$this->save();
}
return $lastMsg;
}
/**
* 获取对话(同时检验对话身份)
* @param $dialog_id
@ -622,7 +609,6 @@ class WebSocketDialog extends AbstractModel
'name' => $name ?: '',
'group_type' => $group_type,
'owner_id' => $owner_id,
'last_at' => in_array($group_type, ['user', 'department', 'all']) ? Carbon::now() : null,
]);
$dialog->save();
foreach (is_array($userid) ? $userid : [$userid] as $value) {
@ -630,7 +616,8 @@ class WebSocketDialog extends AbstractModel
WebSocketDialogUser::createInstance([
'dialog_id' => $dialog->id,
'userid' => $value,
'important' => !in_array($group_type, ['user', 'all'])
'important' => !in_array($group_type, ['user', 'all']),
'last_at' => in_array($group_type, ['user', 'department', 'all']) ? Carbon::now() : null,
])->save();
}
}

View File

@ -458,9 +458,8 @@ class WebSocketDialogMsg extends AbstractModel
WebSocketDialogMsgTodo::whereIn('msg_id', $ids)->delete();
self::whereIn('id', $ids)->delete();
//
$dialogDatas = WebSocketDialog::whereIn('id', $dialogIds)->get();
foreach ($dialogDatas as $dialogData) {
$dialogData->updateMsgLastAt();
foreach ($dialogIds as $dialogId) {
WebSocketDialogUser::updateMsgLastAt($dialogId);
}
foreach ($replyIds as $id) {
self::whereId($id)->update(['reply_num' => self::whereReplyId($id)->count()]);
@ -501,7 +500,7 @@ class WebSocketDialogMsg extends AbstractModel
'data' => [
'id' => $this->id,
'dialog_id' => $this->dialog_id,
'last_msg' => $dialogData->updateMsgLastAt(),
'last_msg' => WebSocketDialogUser::updateMsgLastAt($this->dialog_id),
'update_read' => $deleteRead ? 1 : 0
],
]
@ -923,15 +922,14 @@ class WebSocketDialogMsg extends AbstractModel
'forward_id' => $forward_id,
'forward_show' => $forward_id ? $match[1] : 1,
]);
AbstractModel::transaction(function () use ($dialog, $dialogMsg) {
$dialog->last_at = Carbon::now();
$dialog->save();
AbstractModel::transaction(function () use ($dialogMsg) {
$dialogMsg->send = 1;
$dialogMsg->key = $dialogMsg->generateMsgKey();
$dialogMsg->save();
//
WebSocketDialogUser::whereDialogId($dialog->id)->change([
WebSocketDialogUser::whereDialogId($dialogMsg->dialog_id)->change([
'hide' => 0, // 有新消息时,显示会话(会话内所有会员)
'last_at' => Carbon::now(),
'updated_at' => Carbon::now()->toDateTimeString('millisecond'),
]);
});

View File

@ -11,8 +11,10 @@ use Carbon\Carbon;
* @property int|null $dialog_id 对话ID
* @property int|null $userid 会员ID
* @property string|null $top_at 置顶时间
* @property string|null $last_at 最后消息时间
* @property int|null $mark_unread 是否标记为未读0否1是
* @property int|null $silence 是否免打扰0否1是
* @property int|null $hide 不显示会话0否1是
* @property int|null $inviter 邀请人
* @property int|null $important 是否不可移出(项目、任务人员)
* @property string|null $color 颜色
@ -25,9 +27,11 @@ use Carbon\Carbon;
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereColor($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereDialogId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereHide($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereImportant($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereInviter($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereLastAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereMarkUnread($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereSilence($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTopAt($value)
@ -46,4 +50,17 @@ class WebSocketDialogUser extends AbstractModel
{
return $this->hasOne(WebSocketDialog::class, 'id', 'dialog_id');
}
/**
* 更新对话最后消息时间
* @return WebSocketDialogMsg|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|\Illuminate\Database\Query\Builder|object|null
*/
public static function updateMsgLastAt($dialogId)
{
$lastMsg = WebSocketDialogMsg::whereDialogId($dialogId)->orderByDesc('id')->first();
if ($lastMsg) {
WebSocketDialogUser::whereDialogId($dialogId)->change(['last_at' => $lastMsg->created_at]);
}
return $lastMsg;
}
}

View File

@ -4,6 +4,7 @@ namespace App\Observers;
use App\Models\Deleted;
use App\Models\WebSocketDialogUser;
use Carbon\Carbon;
class WebSocketDialogUserObserver
{
@ -15,6 +16,18 @@ class WebSocketDialogUserObserver
*/
public function created(WebSocketDialogUser $webSocketDialogUser)
{
if (!$webSocketDialogUser->last_at) {
if (in_array($webSocketDialogUser->webSocketDialog?->group_type, ['user', 'department', 'all'])) {
$webSocketDialogUser->last_at = Carbon::now();
$webSocketDialogUser->save();
} else {
$item = WebSocketDialogUser::whereDialogId($webSocketDialogUser->dialog_id)->orderByDesc('last_at')->first();
if ($item?->last_at) {
$webSocketDialogUser->last_at = $item->last_at;
$webSocketDialogUser->save();
}
}
}
Deleted::forget('dialog', $webSocketDialogUser->dialog_id, $webSocketDialogUser->userid);
}

View File

@ -316,12 +316,12 @@ class BotReceiveMsgTask extends AbstractTask
$nameKey = $isManager ? $array[2] : $array[1];
$data = $this->botManagerOne($botId, $msg->userid);
if ($data) {
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->where('web_socket_dialogs.name', 'LIKE', "%{$nameKey}%")
->where('u.userid', $data->userid)
->orderByDesc('u.top_at')
->orderByDesc('web_socket_dialogs.last_at')
->orderByDesc('u.last_at')
->take(20)
->get();
if ($list->isEmpty()) {

View File

@ -0,0 +1,50 @@
<?php
use App\Models\WebSocketDialog;
use App\Models\WebSocketDialogUser;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddWebSocketDialogUsersLastAt extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$isAdd = false;
Schema::table('web_socket_dialog_users', function (Blueprint $table) use (&$isAdd) {
if (!Schema::hasColumn('web_socket_dialog_users', 'last_at')) {
$isAdd = true;
$table->timestamp('last_at')->nullable()->after('top_at')->comment('最后消息时间');
}
});
if ($isAdd) {
// 更新数据
WebSocketDialog::chunk(100, function ($dialogs) {
/** @var WebSocketDialog $dialog */
foreach ($dialogs as $dialog) {
WebSocketDialogUser::whereDialogId($dialog->id)->update(['last_at' => $dialog->last_at]);
}
});
// 删除表字段
Schema::table('web_socket_dialogs', function (Blueprint $table) {
$table->dropColumn("last_at");
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// 回滚数据 - 无法回滚
}
}

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIndexSome20240317 extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
$table->dropIndex(['userid']);
$table->index(['userid', 'dialog_id']);
});
}
/**
* Reverse the migrations.
*
* @return voidw
*/
public function down()
{
// 回滚数据 - 无法回滚
}
}