0

我正在尝试构建一个越来越难的查询...我正在 Laravel 中开发一个聊天应用程序,结构简单:

  • 一个聊天有很多消息。
  • 并且每条消息都属于一个用户。
  • 用户和消息之间的 n:m 以保存已读消息。

所以

聊天.php

public function messages() {
    return $this->hasMany(Message::class)
}

消息.php

public function user() {
    return $this->belongsTo(User::class);
}

public function reads() {
    return $this->belongsToMany(User::class, 'reads');
}

用户.php

public function messages() {
    return $this->hasMany(Message::class);
}

public function reads() {
    return $this->belongsToMany(Message::class, 'reads');
}

好吧,现在我想要下一个查询

给我所有包含我未读消息的聊天(登录用户)

这意味着这样的事情:

Chat::whereDoesntHave('messages.reads', function (Builder $q) {
            return $q->where('user_id', auth()->id());
        });

但那是行不通的,因为如果 Chat 有一条我读过的消息,它会被忽略:(

也许我可以通过仅限于聊天的最后一条消息来实现这一点?或者也许我可以进行这样的操作:

  • 统计所有聊天消息
  • 统计我阅读的所有聊天消息
  • 做一个减法,如果不是 0,考虑这个聊天:D

但我不知道如何用 Eloquent 进行“操作”。

请帮忙。谢谢!

4

2 回答 2

0

好吧,我终于找到了仅获取 Chat 的最后一条消息并检查该消息是否已被特定用户阅读的方法,使用 Query Builder 方法。

在这里,我使用子查询发布了魔术范围;)

public function scopeUnreadBy(Builder $builder, int $userId)
{
    //First, look for Chats with Messages
    return $builder->whereHas('messages', function (Builder $q) use ($userId) { 
        $q->select(['last_message' => function(\Illuminate\Database\Query\Builder $sub) {
            // Then, take only last one Message
            $sub->select('id')
                ->from('messages')
                ->where('chat_id', 'chats.id')
                ->latest()
                ->limit(1);
        }])->whereDoesntHave('reads', function(Builder $q) use ($userId) {
            // Finally, check that last one has not been read :D
            return $q->where('user_id', $userId);
        });
    });
}

呸,这很难。

我希望它对其他人有帮助!

请记住,所有这些都可以通过一个查询来完成;)

于 2019-11-07T19:17:44.633 回答
0

首先从您阅读的所有聊天中提取 id。

$pluckedId=Chat::has('messages.reads', function (Builder $q) {
            return $q->where('user_id', auth()->id());
        })->pluck('id');

然后申请

Chat::whereNotIn('id', $pluckedId )->get();
于 2019-11-05T09:55:29.497 回答