You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel多对多关联下,如何获取会话关联用户及两用户间的会话

原有错误写法的核心原因
  • $user->conversation 不带括号时返回的是当前用户关联的所有会话组成的Eloquent集合,并非单个会话实例,直接链式调用->user是在集合对象上取不存在的属性,自然无法运行。
  • 第二种尝试直接在内存集合上筛选,既没有正确关联到会话下的用户表,还会存在因为提前加载全量数据导致的性能问题,逻辑上也无法覆盖“两个用户同时参与同一会话”的判断。
需求1实现:获取指定用户所有有会话往来的其他用户

优先推荐数据库层面的关联过滤写法,无N+1问题,性能最优:

$targetUserId = 1;
$talkedUsers = User::query()
    ->where('id', '!=', $targetUserId)
    ->whereHas('conversation', function ($query) use ($targetUserId) {
        // 筛出同时关联了当前目标用户的会话
        $query->whereHas('users', function ($queryBuilder) use ($targetUserId) {
            $queryBuilder->where('id', $targetUserId);
        });
    })
    ->get();

如果需要在已加载的用户会话集合上做处理,也可以用集合方法遍历:

$user = User::find(1);
// 预加载关联避免N+1查询
$user->loadMissing('conversation.users');
$talkedUsers = $user->conversation
    // 展开所有会话下的用户列表
    ->flatMap(fn($conversation) => $conversation->users)
    // 排除用户本身
    ->reject(fn($item) => $item->id === $user->id)
    // 按用户ID去重
    ->unique('id')
    ->values();
需求2实现:查询两个指定用户共同参与的所有会话

同样可以直接通过Eloquent关联过滤实现,无需原生SQL:

$userXId = 1;
$userYId = 2;
$sharedConversations = Conversation::query()
    // 会话必须包含用户X
    ->whereHas('users', fn($query) => $query->where('id', $userXId))
    // 会话必须包含用户Y
    ->whereHas('users', fn($query) => $query->where('id', $userYId))
    ->get();

如果已经拿到用户X的模型实例,也可以直接在其关联查询构建器上做过滤,注意这里关联方法要带括号才是查询构建器,不带括号会先把用户X的所有会话加载到内存:

$userX = User::find(1);
$userYId = 2;
$sharedConversations = $userX->conversation()
    ->whereHas('users', fn($query) => $query->where('id', $userYId))
    ->get();

内容的提问来源于stack exchange,提问作者Victoracho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 21:15:03