So I am trying to get my friends and followers statuses with a left join, here is my query:
`/**
* Scope a query to friends and followers statuses.
*
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeFriendsAndFollowers(Builder $query): Builder
{
$user_id = auth()->user()->id;
return $query
->leftJoin('followables', function ($join) {
$join
->on('timeline.owner_id', 'followables.followable_id')
->on('timeline.owner_type', 'followables.followable_type');
})
->leftJoin('friendships', function ($join) {
$join
->on('timeline.owner_id', 'friendships.recipient_id')
->on('timeline.owner_type', 'friendships.recipient_type');
})
->where(function ($query) use($user_id) {
$query
->where(function ($query) use($user_id) {
$query->where('followables.user_id', $user_id);
})
->where('privacy', 'public')
->orWhere('privacy', 'private');
})
->Orwhere(function ($query) use($user_id) {
$query
->where(function ($query) use($user_id) {
$query
->where('friendships.sender_id', $user_id)
->orWhere('friendships.recipient_id', $user_id);
})
->where('privacy', 'public')
->orWhere('privacy', 'private');
})
->orWhere(function ($query) use($user_id) {
$query
->where('timeline.owner_id', $user_id)
->where('timeline.owner_type', User::class);
});
}`
Here is my schema;
Timeline:
Schema::create('timeline', function (Blueprint $table) {
$table->increments('id')->unsigned()->index();
$table->text('status')->nullable();
$table->string('location')->nullable();
$table->string('type')->nullable();
$table->string('privacy')->default('public');
$table->integer('owner_id');
$table->string('owner_type');
$table->timestamps();
$table->softDeletes();
$table->index(['owner_id', 'owner_type']);
$table->index('privacy');
$table->index('owner_id');
});
Friends:
Schema::create(config('friendships.tables.fr_pivot'), function (Blueprint $table) {
$table->increments('id')->unsigned()->index();
$table->morphs('sender');
$table->morphs('recipient');
$table->tinyInteger('status')->default(0);
$table->timestamps();
$table->index(['sender_id', 'recipient_id']);
});
Followers
Schema::create(config('follow.followable_table', 'followables'), function (Blueprint $table) {
$table->increments('id')->unsigned()->index();
$table->unsignedInteger('user_id')->index();
$table->unsignedInteger('followable_id');
$table->string('followable_type');
$table->string('relation')->default('follow')->comment('folllow/like/subscribe/favorite/');
$table->timestamp('created_at');
$table->foreign('user_id')
->references(config('follow.users_table_primary_key', 'id'))
->on(config('follow.users_table_name', 'users'))
->onUpdate('cascade')
->onDelete('cascade');
$table->index(['followable_id', 'followable_type']);
});
Then I run the query like so:
return $this->timeline->select('timeline.*')
->friendsAndFollowers()
->orderBy('timeline.created_at', 'desc')
->paginate(10);
The raw sql query:
SELECT `timeline`.*
FROM `timeline`
LEFT JOIN `followables`
ON `timeline`.`owner_id` = `followables`.`followable_id`
AND `timeline`.`owner_type` = `followables`.`followable_type`
LEFT JOIN `friendships`
ON `timeline`.`owner_id` = `friendships`.`recipient_id`
WHERE ( ( `followables`.`user_id` = :user_id
AND `privacy` = ':public'
OR `privacy` = ':private' )
OR ( ( `friendships`.`sender_id` = :user_id
OR `friendships`.`recipient_id` = :user_id )
AND `privacy` = ':public'
OR `privacy` = ':private' )
OR ( `timeline`.`owner_id` = :user_id
AND `timeline`.`owner_type` = ':class' ) )
ORDER BY `timeline`.`created_at` DESC
And here is the EXPLAIN:
https://i.imgur.com/7qfkNYY.png
I only have 10000 rows in each table, so it's not big at all, I have indexes for the relationships, any idea on what is wrong?