优化 Eloquent 关系检索

Posted

技术标签:

【中文标题】优化 Eloquent 关系检索【英文标题】:Optimizing Eloquent Relationship Retrieval 【发布时间】:2019-08-24 21:19:29 【问题描述】:

我有一个显示平台上社区列表的界面。社区有成员,反过来,成员/个人资料可以互相成为朋友。在列表页面上,每个社区卡都需要显示成员的数量(在社区中)和来自这些成员的朋友(登录个人资料的朋友)的数量。

这是一张公共卡片的示意图

我首先要与成员一起获得社区:

$communities = $loggedInProfile->communities->load('members')->take(15);

然后遍历社区和成员以找出哪些是登录用户的朋友。

   foreach ($communities as $key => $community) 
        $friends = [];
        foreach ($community->members as $member) 
            if ($loggedInProfile->isFriendWith($member)) 
                array_push($friends, $member);
            
        
        $community->members_who_are_friends = $friends;
    

我的问题是,当关联变大时,就查询数量而言,这是非常繁重的。有没有更好的方法来检索这些关系而不必使用嵌套的 for 循环?我还使用 Elasticsearch 索引所有数据。使用 Elasticsearch 进行这种检索会更好吗?这也是hasThrough 的一个很好的用例吗?

更新

members 关系:

public function members()

    return $this->belongsToMany('App\Profile', 'community_members', 'community_id', 'profile_id')->withTimestamps();

isFriendWith 关系:

public function isFriendWith(Model $recipient)

    return $this->findFriendship($recipient)->where('status', Status::ACCEPTED)->exists();

检查是在名为friendships 的表上完成的。检查status 列(可以是0 或1)以查看是否为朋友。

findFriendship 支票:

private function findFriendship(Model $recipient)

    return Friendship::betweenModels($this, $recipient);

数据库结构:

-配置文件迁移

Schema::create('profiles', function (Blueprint $table) 
            $table->increments('id');
            $table->unsignedInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users');
);

-社区迁移(外键为社区的owner

Schema::create('communities', function (Blueprint $table) 
    $table->increments('id');
    $table->unsignedInteger('profile_id');
    $table->foreign('profile_id')->references('id')->on('profiles');
    $table->string('slug')->unique();
);

-Community_members 迁移

Schema::create('community_members', function (Blueprint $table) 
    $table->primary(['profile_id', 'community_id']);
    $table->unsignedInteger('profile_id');
    $table->foreign('profile_id')->references('id')->on('profiles');
    $table->unsignedInteger('community_id');
    $table->foreign('community_id')->references('id')->on('communities');
    $table->timestamps();
);

-友谊迁移

Schema::create('friendships'), function (Blueprint $table) 
    $table->increments('id');
    $table->morphs('sender');
    $table->morphs('recipient');
    $table->tinyInteger('status')->default(0);
    $table->timestamps();
);

【问题讨论】:

你能告诉我函数 getMutualFriends 吗?您在那里使用 $member 的哪个字段? 抱歉,使用了错误的友谊检查。更新了问题。成员是我正在迭代的社区的成员。我正在遍历社区中的 members() 关系。 给我看function isFriendWith($member),或者告诉我$member的w/c字段你用它来知道它是否相互 更新问题。 member 是 User right 的一个实例?与loggedUser相同.. 【参考方案1】:

在你的行中:

$communities = $loggedInProfile->communities->load('members')->take(15);

load() 用于执行 Lazy Eager 加载,即您在检索到社区后加载成员,从而导致每个社区的查询不同。您可以使用with() 通过单个查询提取整个数据。此外,take(15) 是在结果集合上执行的,而不是在查询上执行的。试试这个:

$communities = $loggedInProfile->communities()->with('members')->take(15)->get();

【讨论】:

我尝试了这两种方法,但似乎并不影响正在运行的查询数量:/.

以上是关于优化 Eloquent 关系检索的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Eloquent - 从关系中检索数据

Laravel/Eloquent ORM - 仅检索引用的记录

Laravel Eloquent - 从相关模型中检索特定列

使用 eloquent 和 vuejs 时如何检索数据库列

laravel eloquent 中的一对多关系

Eloquent与条件有很多关系