Возврат унифицированного JSON отношения «многие ко многим» в Laravel

#php #sql #json #laravel

Вопрос:

Я не могу свыкнуться с этим. У меня есть три таблицы (сокращенно):

 *images*
id | label | …

*keywords*
id | label | …

*image_keyword*
image_id | keyword_id
 

И у меня есть их много-много отношений, определенных в моделях:

 *Image.php*
public function keywords()
{
    return $this->belongsToMany(Keyword::Class);
}

*Keyword.php*
public function images()
{
    return $this->belongsToMany(Image::Class);
}
 

В какой-то момент я реализовал ленивый нечеткий поиск с помощью этого кода:

 $terms = explode(' ', $request->input('q'));
$query = DB::connection('pia')->table('images');

foreach($terms as $k => $term) {
    $query->where(DB::raw('lower(images.title)'), 'like', '%' . strtolower($term) . '%');
}

return response()->json($query->get());
 

На данный момент это прекрасно работает. Теперь я хотел бы добавить ключевые слова к объектам изображений, которые я передаю обратно на интерфейс, но мне не удается создать рабочее решение. Я не эксперт в области проектирования баз данных и кода.

Я бы хотел, чтобы ключевые слова просто передавались вместе с объектом изображения, как это:

 {
    'id': 123,
    'label': 'Dog',
    'file': '/data/images/dog.jpg',
    'keywords': [
        {
            'id': 312,
            'label': 'Animal'
        },
        {
            'id': 313,
            'label': 'Pet'
    ],
}
 

Я попробовал присоединиться, но не смог добиться никаких рабочих результатов.

Ответ №1:

Я думаю, что у вас есть два решения для этого

1 — вы можете попробовать присоединиться вот так

 $query = DB::connection('pia')->table('images');
$query->select('images.*','keywords.id,label')      
        ->join('image_keyword','images.id','image_keyword.image_id')
        ->leftJoin('keywords','image_keyword.keyword_id','keywords.id');
foreach($terms as $k => $term) {
    $query->where(DB::raw('lower(images.title)'), 'like', '%' . strtolower($term) . '%');
};
return response()->json($query->groupBy(images.id)->get());
        
 

2 — самое простое решение-использовать модель laravel eloquent примерно так

 $query = Image::with('keywords:id,label');
foreach($terms as $k => $term) {
    $query->where(DB::raw('lower(images.title)'), 'like', '%' . strtolower($term) . '%');
}

return response()->json($query->get());
 

Комментарии:

1. Второй пример сработал как заклинание, и он прекрасен. Я перечеркнул ключевое слово with, но как-то неправильно его реализовал или что-то в этом роде. Большое спасибо.