【问题标题】:Is it possible to grouping by from and to user id in Laravel 8是否可以在 Laravel 8 中按 from 和 to user id 分组
【发布时间】: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 有一些特殊的工具来简化这个常见任务)。

标签: php mysql laravel database-design laravel-8


【解决方案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));
    }

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

【讨论】:

  • 正确。我有相同的群聊结构。和工作发现。我只是想要如上所述,因为它已经构建了架构,这就是原因。
  • 老实说,我首先尝试使用您的结构。但我意识到处理它非常困难。这就是为什么我建议你改变结构。数据库对组和私有使用相同的结构会很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 2022-12-02
  • 2011-03-16
  • 1970-01-01
  • 2013-06-26
相关资源
最近更新 更多