Запрос непрочитанных сообщений пользователем в чате - PullRequest
0 голосов
/ 05 ноября 2019

Я пытаюсь создать сложный запрос ... Я разрабатываю приложение чата в Laravel, с простой структурой:

  • Чат имеет много сообщений.
  • И каждое сообщение принадлежит пользователю.
  • n: m между пользователями и сообщениями для сохранения прочитанных сообщений.

Итак

Chat.php

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

Message.php

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

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

User.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());
        });

Но это не работает, потому что если в чате есть только одно прочитанное мною Сообщение, оно игнорируется: (

Может быть, я мог бы достичь этого, просматривая сообщение LAST только в чате? Или, может быть, я могу сделать такую ​​операцию:

  • Подсчитать все сообщения в чате
  • Подсчитать все сообщения в чате, прочитанные мной
  • Сделать вычитание,если не 0, рассмотрите этот чат: D

Но я не знаю, как выполнить эту «операцию» с Eloquent.

Пожалуйста, помогите. Спасибо!

Ответы [ 2 ]

0 голосов
/ 07 ноября 2019

Что ж, я в конце концов нашел способ извлечь только последнее сообщение чата и проверить, было ли оно прочитано определенным пользователем, используя подход 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);
        });
    });
}

Фу, это было сложно.

Надеюсь, это поможет кому-то еще!

И помните, все можно сделать одним запросом;)

0 голосов
/ 05 ноября 2019

первый идентификатор для всех чатов, которые вы прочитали.

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

Затем примените

Chat::whereNotIn('id', $pluckedId )->get();
...