Где НЕ в сводной таблице
В Laravel мы можем настроить такие отношения:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Позволяет нам получить все элементы в сводной таблице для пользователя:
Auth::user()->items();
Однако, если я хочу получить противоположное. И получите все элементы, которые пользователь НЕ ДОЛЖЕН. Поэтому НЕ в сводной таблице.
Есть ли простой способ сделать это?
Ответы
Ответ 1
Для простоты и симметрии вы можете создать новый метод в модели User:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
Чтобы использовать вызов:
Auth::user()->availableItems();
Ответ 2
Посмотрев исходный код класса Illuminate\Database\Eloquent\Builder
, у нас есть два метода в Laravel: whereDoesntHave
(напротив whereHas
) и doesntHave
(напротив has
)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
это работает правильно для меня!
Для простого "Где не существует отношения" используйте это:
User::doesntHave('Role')->get();
Извините, не понимаю английский. Я использовал переводчик Google.
Ответ 3
Это не так просто, но обычно наиболее эффективным способом является использование подзапроса.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
Если бы это было то, что я часто делал, я бы добавил его как метод области к модели Item.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Затем используйте это позже.
$items = Item::whereNotRelatedToUser($user_id)->get();
Ответ 4
Как насчет левого соединения?
Предполагая, что таблицы users
, items
и item_user
найти все items
, не связанные с пользователем 123
:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();
Ответ 5
это должно работать для вас
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);
Ответ 6
Закончено создание области для этого так:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
И затем вызовите:
Items::avail()->get();
Работает пока, но немного грязно. Хотелось бы увидеть что-то с ключевым словом вроде not
:
Auth::user()->itemsNot();
В основном Eloquent запускает вышеуказанный запрос в любом случае, за исключением =
вместо <>
.
Ответ 7
Возможно, вы можете использовать:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Источник: http://laravel.com/docs/4.2/queries#advanced-wheres