Самым оптимальным способом было бы сделать объединение:
Chat::join('chat_user', 'chat_id', 'chats.id')
->whereIn('chat_user.user_id',$listOfUserIds)
->selectRaw('chat_user.chat_id, COUNT(1) as users_count')
->groupBy('chat_user.chat_id')
->having('users_count','=', count($listOfUserIds));
Это оптимально, потому что оно присоединяется только к стержню.
Хотя элегантный способ сделать это - использовать whereHas
с параметрами "кардинальности", т. Е. Найти все чаты, в которых участвуют эти пользователи, пока все они задействованы.
Chat::whereHas('user', function ($q) {
return $q->whereIn('id', $listOfUserIds);
}, '=', count($listOfUserIds));
это все еще выполняет только один запрос, но объединяет сводку и таблица пользователей.