Laravel Eloquent:with()vs join()JSON输出

时间:2019-05-24 20:17:11

标签: json laravel eloquent

我在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
            }
        }
    }

如何使第一个查询返回与第二个查询相同的3个级别?

为什么会这样?

2 个答案:

答案 0 :(得分:1)

第一个是更多地利用查询生成器,并将执行一个如下所示的查询:

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());

答案 1 :(得分:1)

之所以会这样,是因为在第二个查询中,您将eager loading用于雄辩的关系。雄辩的模型的默认<script src="https://unpkg.com/vue"></script> <div id="app"> <expandable> <p>no model</p> </expandable> <expandable v-model="isOpen"> <p>has model</p> </expandable> </div>方法将其属性和已加载的关系合并到一个表示中。

另一方面,您的第一个查询将联接表,但不会加载任何关系。因此,最简单的方法是像在第二个查询中一样,渴望在第一个查询中加载这些关系:

toArray()

请注意,这将对 $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查询,以急于加载到它们各自的关系中。