如何同时查询多条主记录的涉外关系数据
How to query foreign relations data along with multiple main records
我有一个关系Room
。每个房间有一个所有者,是 User
个实体,每个 Room
有多个参与者,也是 User
个实体。
当页面加载时,我在 React 中查询所有房间
一旦所有的房间都被 return 回传,我用每个房间的 ID 一个一个地查询数据库,以取回存储在其他关系中的房间的详细信息(房间所有者、房间用户数、属于实体 Topic
)
的房间主题
const fetchRooms = () => {
const csrf: HTMLMetaElement = document.querySelector(
"meta[name='csrf-token']"
) as HTMLMetaElement;
axios
.post(
`/room/all/${pageNumber}`,
{},
{
headers: {
"Content-type": "application/json",
"X-CSRF-TOKEN": csrf.content,
},
}
)
.then((response) => {
const data = response.data;
data.forEach((room: any) => {
//! TODO: merge each rooms details with its own data to avoid extra requests
axios
.post(
"/room/details",
{ id: room.id },
{
headers: {
"Content-type": "application/json",
"X-CSRF-TOKEN": csrf.content,
},
}
)
.then(({ data }) => {
if (data) {
setRooms((rooms) => [
...rooms,
<RoomCard
key={room.id}
id={room.id}
title={room.name}
img={null}
username={data.owner.username}
timestamp={room.created_at}
userCount={data.user_count}
topic={data.topic.name}
/>,
]);
}
});
});
})
.catch(({ response }) => {
console.log(response.status, response.data);
});
};
laravel 处理
// web.php
Route::controller(RoomController::class)->group(function () {
Route::post("room/all/{page:int}", "all")->name("rooms.all");
Route::post("room/details", "details")->name("rooms.details");
}
// RoomController.php
public function all(Request $request, $page = 1)
{
if (!Auth::check()) {
return response("", 403);
}
$total_posts = 20;
$rooms = Room::offset(($page - 1) * $total_posts)->limit($total_posts)->orderBy("id", "desc")->get();
return response()->json($rooms);
}
public function details(Request $request)
{
if ($request->id) {
$room = Room::find($request->id);
$user_count = RoomUser::where("room_id", $room->id)->count() + 1;
return response()->json(["owner" => $room->owner, "user_count" => $user_count, "topic" => $room->topic]);
}
return response("", 403);
}
DB info
+------------------------+
| Tables_in_project |
+------------------------+
| failed_jobs |
| migrations |
| password_resets |
| personal_access_tokens |
| room_users |
| rooms |
| topics |
| users |
+------------------------+
Users
+-------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| username | varchar(255) | NO | UNI | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| email_verified_at | timestamp | YES | | NULL | |
| password | varchar(255) | NO | | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| profile_picture | varchar(255) | YES | | NULL | |
| privilege_level | int(11) | NO | | 0 | |
+-------------------+---------------------+------+-----+---------+----------------+
Rooms
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| description | text | YES | | NULL | |
| topic_id | bigint(20) unsigned | NO | MUL | NULL | |
| owner_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
Topics
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| name | varchar(255) | NO | UNI | NULL | |
+------------+---------------------+------+-----+---------+----------------+
Users in rooms
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| room_id | bigint(20) unsigned | NO | MUL | NULL | |
| user_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+------------+---------------------+------+-----+---------+----------------+
我遇到的问题是,这是非常非常低效的,因为我必须为每个房间分别查询房间的详细信息,这在部署后会非常慢,甚至更慢在我的本地机器上。
我不确定如何处理它。
我知道的一种方法是使用 Laravel 提供的关系,但还有另一个问题
当我查询所有房间时,我 return 他们回来了。用户模型函数(访问一对一和一对多等关系的函数)仅在 Laravel 中可用,当然它们不会与对 JS 的响应一起返回。
如何查询 rooms
table 并包含与房间相关的所有信息(主题、所有者、房间中的所有用户;他们的 ID 存储在 room_users
, 所有用户计数)
我正在使用:
- ReactJS 17.0.2
- Laravel 9
- PHP 8.1
- MySQL 版本 15.1 分发 10.7.3-MariaDB
感谢 ynber 帮助评论。
我用eloquent中的with
函数解决了。
在 RoomController
的 all
函数中,我将查询更改为
$rooms = Room::with(["topic", "owner", "users"])->offset(($page - 1) * $total_posts)->limit($total_posts)->orderBy("id", "desc")->get();
传递给 with
的数组需要在 Room
的模型中定义函数名称,在我的例子中如下所示
public function topic()
{
return $this->belongsTo(Topic::class);
}
public function owner()
{
return $this->belongsTo(User::class);
}
public function users()
{
return $this->belongsToMany(User::class, "room_users");
}
我有一个关系Room
。每个房间有一个所有者,是 User
个实体,每个 Room
有多个参与者,也是 User
个实体。
当页面加载时,我在 React 中查询所有房间
一旦所有的房间都被 return 回传,我用每个房间的 ID 一个一个地查询数据库,以取回存储在其他关系中的房间的详细信息(房间所有者、房间用户数、属于实体 Topic
)
const fetchRooms = () => {
const csrf: HTMLMetaElement = document.querySelector(
"meta[name='csrf-token']"
) as HTMLMetaElement;
axios
.post(
`/room/all/${pageNumber}`,
{},
{
headers: {
"Content-type": "application/json",
"X-CSRF-TOKEN": csrf.content,
},
}
)
.then((response) => {
const data = response.data;
data.forEach((room: any) => {
//! TODO: merge each rooms details with its own data to avoid extra requests
axios
.post(
"/room/details",
{ id: room.id },
{
headers: {
"Content-type": "application/json",
"X-CSRF-TOKEN": csrf.content,
},
}
)
.then(({ data }) => {
if (data) {
setRooms((rooms) => [
...rooms,
<RoomCard
key={room.id}
id={room.id}
title={room.name}
img={null}
username={data.owner.username}
timestamp={room.created_at}
userCount={data.user_count}
topic={data.topic.name}
/>,
]);
}
});
});
})
.catch(({ response }) => {
console.log(response.status, response.data);
});
};
laravel 处理
// web.php
Route::controller(RoomController::class)->group(function () {
Route::post("room/all/{page:int}", "all")->name("rooms.all");
Route::post("room/details", "details")->name("rooms.details");
}
// RoomController.php
public function all(Request $request, $page = 1)
{
if (!Auth::check()) {
return response("", 403);
}
$total_posts = 20;
$rooms = Room::offset(($page - 1) * $total_posts)->limit($total_posts)->orderBy("id", "desc")->get();
return response()->json($rooms);
}
public function details(Request $request)
{
if ($request->id) {
$room = Room::find($request->id);
$user_count = RoomUser::where("room_id", $room->id)->count() + 1;
return response()->json(["owner" => $room->owner, "user_count" => $user_count, "topic" => $room->topic]);
}
return response("", 403);
}
DB info
+------------------------+
| Tables_in_project |
+------------------------+
| failed_jobs |
| migrations |
| password_resets |
| personal_access_tokens |
| room_users |
| rooms |
| topics |
| users |
+------------------------+
Users
+-------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| username | varchar(255) | NO | UNI | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| email_verified_at | timestamp | YES | | NULL | |
| password | varchar(255) | NO | | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| profile_picture | varchar(255) | YES | | NULL | |
| privilege_level | int(11) | NO | | 0 | |
+-------------------+---------------------+------+-----+---------+----------------+
Rooms
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| description | text | YES | | NULL | |
| topic_id | bigint(20) unsigned | NO | MUL | NULL | |
| owner_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
Topics
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| name | varchar(255) | NO | UNI | NULL | |
+------------+---------------------+------+-----+---------+----------------+
Users in rooms
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| room_id | bigint(20) unsigned | NO | MUL | NULL | |
| user_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+------------+---------------------+------+-----+---------+----------------+
我遇到的问题是,这是非常非常低效的,因为我必须为每个房间分别查询房间的详细信息,这在部署后会非常慢,甚至更慢在我的本地机器上。
我不确定如何处理它。
我知道的一种方法是使用 Laravel 提供的关系,但还有另一个问题
当我查询所有房间时,我 return 他们回来了。用户模型函数(访问一对一和一对多等关系的函数)仅在 Laravel 中可用,当然它们不会与对 JS 的响应一起返回。
如何查询 rooms
table 并包含与房间相关的所有信息(主题、所有者、房间中的所有用户;他们的 ID 存储在 room_users
, 所有用户计数)
我正在使用:
- ReactJS 17.0.2
- Laravel 9
- PHP 8.1
- MySQL 版本 15.1 分发 10.7.3-MariaDB
感谢 ynber 帮助评论。
我用eloquent中的with
函数解决了。
在 RoomController
的 all
函数中,我将查询更改为
$rooms = Room::with(["topic", "owner", "users"])->offset(($page - 1) * $total_posts)->limit($total_posts)->orderBy("id", "desc")->get();
传递给 with
的数组需要在 Room
的模型中定义函数名称,在我的例子中如下所示
public function topic()
{
return $this->belongsTo(Topic::class);
}
public function owner()
{
return $this->belongsTo(User::class);
}
public function users()
{
return $this->belongsToMany(User::class, "room_users");
}