是否可以在 Laravel 8 中按 from 和 to user id 分组

Posted

技术标签:

【中文标题】是否可以在 Laravel 8 中按 from 和 to user id 分组【英文标题】:Is it possible to grouping by from and to user id in Laravel 8 【发布时间】:2021-12-06 22:53:07 【问题描述】:

我有一对一的聊天简单表,其中消息存储从用户 ID 到用户 ID。这是架构。

我通过将 from_user_id 匹配与登录用户或 to_user_id 匹配来检索两个用户之间的对话

->where(function($q) use($user_id) 
       $q->where('from_user_id', $user_id)
       ->orWhere('to_user_id', $user_id);
)

现在我想要登录用户和其他用户之间的独特对话。我试过了

->groupBy('from_user_id', 'to_user_id')

但它同时返回记录 ID:1 和 6,因为它存储为 65 - 66 和 66 - 65。

因此,我可以通过独特的对话进行分组并仅获得一条记录。或者我需要将表的架构更改为会话和会话消息。

请指导我。 谢谢。

【问题讨论】:

您可以按原始表达式进行分组,例如(调整语法)->groupBy(db::RAW('LEAST(from_user_id,to_user_id), GREATEST(from_user_id,to_user_id)')) @Akina 非常感谢。它给出了唯一的记录,但是从那个重复的记录 order by 不起作用,是否可以从相同的记录中获取最新记录? 使用显示的分组获得组的最大日期时间。使用它作为子查询从另一个表副本中选择相应的行。这在纯 SQL 中很简单——但我不使用 Laravel,因此我不知道它会是什么样子(也许 Laravel 有一些特殊的工具来简化这个常见任务)。 【参考方案1】:

我建议添加一个对话模型。基本上,您需要为每个用户到用户的关系(以及其中的所有消息)设置一个唯一标识符,而对话模型将是实现这一目标的最简洁的方法。

话虽如此,有一些聪明的方法可以在没有额外模型的情况下做你想做的事。由于您知道登录用户的 ID,因此您可以将回调传递给 Collection 的 groupBy 方法,该方法按 不是登录用户的 ID 分组。例如:

->where(function($query) 
    $query->where('from_user_id', $user_id)
    ->orWhere('to_user_id', $user_id)
)
// So the messages appear in order.
->orderByDesc('created_at')
->get()
->groupBy(function($item) use ($user_id) 
    // If the message was sent by the user, it groups on the recipient's ID.
    // If the message was received by the user, it groups on the sender's ID.
    return $item->from_user_id == $user_id ? $item->to_user_id : $item->from_user_id;
);

此示例未考虑用户向自己发送消息(这可能在您的系统中),因此可能需要微调。

【讨论】:

感谢@James 的回复,我知道第一次谈话的事情。但它已经开发了,所以找到了解决方案。您的第二个答案不起作用,它对数据进行分组,但在组内提供所有记录。我想在查询组中而不是在集合中。 不要计划拥有数百万行; "or" 的表现不好。【参考方案2】:

最近,我为我的公司编写了一个聊天系统。我尝试了许多模式,但最终找到了最好的一个。我可以和你分享。

此架构可能包含多个表,并会迫使您发送更多请求。但在这种结构中,您将能够轻松处理所有任务。这是模型和控制器结构:

聊天消息:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class ChatMessage extends Model

    use HasFactory;
    
    public $table = "chat_messages";

    protected $fillable = ['chat_id', 'user_id','content'];
    
    public function chat()
    
        return $this->belongsTo(ChatUser::class, 'chat_id', 'id');
    
    
    public function user()
    
        return $this->belongsTo(User::class);
    

聊天用户:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class ChatUser extends Model

    use HasFactory;

    public $table = "chat_users";

    protected $fillable = ['user_id_from', 'user_id_to','last_activity'];
    protected $dates = ['last_activity']; 

    public function user_from()
    
        return $this->belongsTo(User::class, 'user_id_from', 'id');
    
    
    public function user_to()
    
        return $this->belongsTo(User::class, 'user_id_to', 'id');
    
    
    public function messages()
    
        return $this->hasMany(ChatMessage::class, 'chat_id', 'id')->latest('id')->take(15);
    

聊天控制器:

    public function index()
    
        $chats = ChatUser::has('messages')
            ->where('user_id_from', $this->user->id)
            ->orWhere(function ($query)  
                $query->where('user_id_to' , $this->user->id);
            )
            ->with(['user_to','user_from'])
            ->orderBy('last_activity', 'DESC')
            ->get();

        return $this->successResponse(new ChatCollection($chats));
    

如果您有任何问题,请不要犹豫。

【讨论】:

正确。我有相同的群聊结构。和工作发现。我只是想要如上所述,因为它已经构建了架构,这就是原因。 老实说,我首先尝试使用您的结构。但我意识到处理它非常困难。这就是为什么我建议你改变结构。数据库对组和私有使用相同的结构会很好。

以上是关于是否可以在 Laravel 8 中按 from 和 to user id 分组的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 8 数据库小笔记

Laravel 8 数据库小笔记

Laravel 8 数据库小笔记

如何在 Laravel 中按日期排序消息

Laravel 4.1 多对多关系和条件在哪里?

如何在 Laravel 的嵌套 2 级关系中按列排序?