使用 Laravel (Lumen/Eloquent) 查询多对多关系和更多数据
Querying many-to-many relation and some more data with Laravel (Lumen/Eloquent)
我有三个table。
Table 1: posts
// 存储用户post的twitter
Table 2: tags
// 存储 twitter 中使用的标签 posts
Table 3: post_tag
// 枢轴-table
现在,我想输入一个tag
,例如'yolo' 并获取所有具有此主题标签的 post。这很容易,我已经这样做了
Class Post:
/**
* Get the tags associated with the post
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tags()
{
return $this->belongsToMany('App\Models\Tag')->get(['tag']);
}
Class 标签:
/**
* Get the posts associated with the given tag
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function posts()
{
return $this->belongsToMany('App\Models\Post');
}
访问数据:
/** @var Tag $tag */
try {
$tag = Tag::where('tag', urldecode($passedTag))->firstOrFail();
return response()->json(['posts' => $tag->posts->toArray()]);
} catch (ModelNotFoundException $e) {
return response()->json(['errors' => 'No query results for: '. $passedTag]);
}
但是,我还想做的是,还获取已用于 post 的所有其他标签。例如。 post 有标签 yolo
和 swag
。现在,当用户输入 yolo
时,我希望应用程序显示所有 post 被标记为 yolo
,但也显示 post 具有的所有其他标记,在此示例中swag
。我这样做过
/** @var Tag $tag */
try {
$tag = Tag::where('tag', urldecode($passedTag))->firstOrFail();
$posts = $tag->posts;
$fData = [];
foreach ($posts as $index=>$post) {
/** @var Post $post */
$fData[$index] = $post->toArray();
$fData[$index]['tags'] = $post->tags();
}
return response()->json(['posts' => $fData]);
} catch (ModelNotFoundException $e) {
return response()->json(['errors' => 'No query results for: '. $passedTag]);
}
但由于我是 Laravel (Lumen) 的新手,所以我很确定有一种更快的方法可以做到这一点。有什么建议可以提高性能吗?谢谢! :)
您可以Eager load 所有需要的关系。它们也会显示在 toArray
中。
/** @var Tag $tag */
try {
return response()->json([
'posts' => Tag::with('posts')->with([
'posts.tags' => function ($query) {
$query->addSelect(['tag']);
}
])
->where('tag', urldecode($passedTag))
->firstOrFail()->posts->toArray()
]);
} catch (ModelNotFoundException $e) {
return response()->json(['errors' => 'No query results for: '. $passedTag]);
}
预加载意味着您可以在检索对象本身时预加载对象的任何关系。这不仅会减少查询负载,还会为您提供所需的所有数据,而无需额外的循环或数据库调用。如您所见,您可以嵌套预加载,以加载关系的关系 - posts.tags
编辑
这种预加载关系只会从相关标签中获取标签列:
'posts.tags' => function ($query) {
$query->addSelect(['tag']);
}
我有三个table。
Table 1: posts
// 存储用户post的twitter
Table 2: tags
// 存储 twitter 中使用的标签 posts
Table 3: post_tag
// 枢轴-table
现在,我想输入一个tag
,例如'yolo' 并获取所有具有此主题标签的 post。这很容易,我已经这样做了
Class Post:
/**
* Get the tags associated with the post
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tags()
{
return $this->belongsToMany('App\Models\Tag')->get(['tag']);
}
Class 标签:
/**
* Get the posts associated with the given tag
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function posts()
{
return $this->belongsToMany('App\Models\Post');
}
访问数据:
/** @var Tag $tag */
try {
$tag = Tag::where('tag', urldecode($passedTag))->firstOrFail();
return response()->json(['posts' => $tag->posts->toArray()]);
} catch (ModelNotFoundException $e) {
return response()->json(['errors' => 'No query results for: '. $passedTag]);
}
但是,我还想做的是,还获取已用于 post 的所有其他标签。例如。 post 有标签 yolo
和 swag
。现在,当用户输入 yolo
时,我希望应用程序显示所有 post 被标记为 yolo
,但也显示 post 具有的所有其他标记,在此示例中swag
。我这样做过
/** @var Tag $tag */
try {
$tag = Tag::where('tag', urldecode($passedTag))->firstOrFail();
$posts = $tag->posts;
$fData = [];
foreach ($posts as $index=>$post) {
/** @var Post $post */
$fData[$index] = $post->toArray();
$fData[$index]['tags'] = $post->tags();
}
return response()->json(['posts' => $fData]);
} catch (ModelNotFoundException $e) {
return response()->json(['errors' => 'No query results for: '. $passedTag]);
}
但由于我是 Laravel (Lumen) 的新手,所以我很确定有一种更快的方法可以做到这一点。有什么建议可以提高性能吗?谢谢! :)
您可以Eager load 所有需要的关系。它们也会显示在 toArray
中。
/** @var Tag $tag */
try {
return response()->json([
'posts' => Tag::with('posts')->with([
'posts.tags' => function ($query) {
$query->addSelect(['tag']);
}
])
->where('tag', urldecode($passedTag))
->firstOrFail()->posts->toArray()
]);
} catch (ModelNotFoundException $e) {
return response()->json(['errors' => 'No query results for: '. $passedTag]);
}
预加载意味着您可以在检索对象本身时预加载对象的任何关系。这不仅会减少查询负载,还会为您提供所需的所有数据,而无需额外的循环或数据库调用。如您所见,您可以嵌套预加载,以加载关系的关系 - posts.tags
编辑
这种预加载关系只会从相关标签中获取标签列:
'posts.tags' => function ($query) {
$query->addSelect(['tag']);
}