如何同时查询多条主记录的涉外关系数据

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 , 所有用户计数)

我正在使用:

感谢 ynber 帮助评论。

我用eloquent中的with函数解决了。

RoomControllerall 函数中,我将查询更改为

$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");
    }