Laravel Eloquent: с () vs join () вывод JSON - PullRequest
0 голосов
/ 24 мая 2019

У меня есть два запроса на мой проект Laravel:

$questions = \App\Answer::rightJoin('questions','answers.id_question','=','questions.id_question')
        ->leftJoin('users','answers.id_user','=','users.id')->where([
            ['questions.id_question', '=', $id_question],
            ['questions.flg_active', '=', true],
        ])->orderBy('questions.created_at', 'desc')->paginate(5);   

и

 $questions = \App\Answer::with('question.user')
    ->orderBy('created_at', 'desc')->paginate(15);

По сути, первый ответ на вопросы, которые еще не получены, а второй - только вопросы, на которые уже дан ответ.Я пытаюсь использовать один и тот же блэйд-вид для обоих, но они имеют разную структуру вывода JSON.

Первый возвращает одноуровневый JSON, а второй возвращает 3 уровня данных.

"data": [{
        "id_answer": 42,
        "created_at": "2018-11-28 17:52:18",
        "updated_at": "2019-05-24 15:09:14",
        "id_user": 2,
        "id_question": 42,
        "str_answer": "onono onooono nonono onn ",
        "str_question": "ononon ononon onononn ?",
        "url_link": null,
        "flg_active": 1,
        "id": 1,
        "name": "Paul",
        "surname": null,
        "email": "p@yahoo.com",
        "certification": "CFA ...",
        "about": "CS, ....."
    }

и:

"data": [{
        "id_answer": 64,
        "created_at": "2019-05-16 15:46:54",
        "updated_at": "2019-05-16 15:46:54",
        "id_user": 2,
        "id_question": 98,
        "str_answer": "onono non ooonononn",
        "question": {
            "id_question": 98,
            "created_at": "2019-05-16 15:06:31",
            "updated_at": "2019-05-16 15:24:43",
            "id_user": 2,
            "str_question": "onono onnon ononon?",
            "url_link": null,
            "flg_active": 1,
            "user": {
                "id": 2,
                "name": "Paul",
                "surname": null,
                "email": "p@outlook.com",
                "created_at": "2018-12-06 05:50:09",
                "updated_at": "2019-05-24 11:23:32",
                "certification": null,
                "about": null
            }
        }
    }

Как сделать так, чтобы первый вернулся на тех же трех уровнях, что и второй запрос?

Почему это происходит?

Ответы [ 2 ]

1 голос
/ 25 мая 2019

Это происходит потому, что во втором запросе вы используете готовую загрузку для своих отношений Eloquent.Метод toArray() по умолчанию в Eloquent модели объединяет как ее атрибуты, так и загруженные отношения в одно представление.

С другой стороны, ваш первый запрос объединяет таблицы, но не загружает никаких связей.Поэтому самый простой способ сделать это - загрузить эти отношения в свой первый запрос так же, как во втором:

    $questions = \App\Answer::with('questions.user')           
        ->rightJoin('questions','answers.id_question','=','questions.id_question')
        ->leftJoin('users','answers.id_user','=','users.id')->where([
            ['questions.id_question', '=', $id_question],
            ['questions.flg_active', '=', true],
        ])->orderBy('questions.created_at', 'desc')->paginate(5);

Обратите внимание, что это приведет к дополнительным запросам SELECT ... WHERE id IN (...)для обеих моделей Question и User, которые необходимо загружать в соответствующие отношения.

1 голос
/ 24 мая 2019

Первый больше использует построитель запросов и выполнит один запрос, который будет выглядеть примерно так:

SELECT * FROM answer
RIGHT JOIN questions ON answers.id_question = questions.id_question
LEFT JOIN users ON answers.id_user = users.id
WHERE questions.id_question = $id_question
AND questions.flg_active = true
ORDER BY questions.created_at desc
OFFSET 0
LIMIT 15

Этот запрос возвращает данные из всех таблиц в точности так, как их вычисляет sql.Laravel / Eloquent не знает, как надежно поместить это в красноречивый формат.

Второй выполнит 3 запроса, которые будут выглядеть примерно так:

SELECT * FROM answer
ORDER BY created_at desc
OFFSET 0
LIMIT 15

SELECT * FROM question
WHERE answer_Id IN ($answer_ids) // Will be like (1, 5, 6, 7). All the ids retrieve from the first query

SELECT * FROM user
WHERE queston_id IN ($user_ids)

Поэтому Eloquent выполняет 3 запросаон может надежно создать структуру, которую вы обрисовали.

В конечном итоге это компромисс, первый вариант быстрее, но с ответом сложнее работать в php, который создает менее читаемый код.

Я рекомендуювы смотрите на запросы, которые выполняются каждым из них, используя встроенный журнал запросов.

\DB::enableQueryLog();
$builtQuery->get()
dd(\DB::getQueryLog());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...