eloquent-has-many-deep: Retrieving duplicate models in collection

Hello,

I currently have the following relations;

Collective → hasMany → Artist → belongsToMany → Video

I currently have the following hasManyDeep relation setup for a collective to fetch their videos.

public function videos()
{
    return $this->hasManyDeep(Video::class, [Artist::class, 'artist_video']);
}

However, when I fetch the videos for a collective using $collective->videos I receive duplicate videos since an the same artists in a collective, can be assigned to the same video.

How can I ensure that only unique videos are fetched? Is there something wrong with my relation?

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 21 (9 by maintainers)

Most upvoted comments

For anyone finding this in 2021. HasManyDeep relationship declarations accept ->distinct() as an added chain at the end of the relationship declaration. No guarantees that it’ll always work, but in our use case it worked perfectly to return only unique results of the distant relation.

I found a solution, check out v1.1. You can now use pagination with ->groupBy('videos.id') to get unique results.

For anyone finding this in 2021. HasManyDeep relationship declarations accept ->distinct() as an added chain at the end of the relationship declaration. No guarantees that it’ll always work, but in our use case it worked perfectly to return only unique results of the distant relation.

Is also use this, but at least for MySQL8, PHP8 and Laravel 8.x I can say that it does’t not work for all cases. For example count is applied before the distinct filter, so the count result might be bigger than the distinct results when using this. This can - depending on your app - break pagination etc.

When using distinct and there are multiple relations in between that point to the same target model there would be a different result between: $model->deepRelation->count() // only distinct results are counted and $model->deepRelation()->count() // also between (join) records are counted

So if you have an influence on how the pagination works, you would need to change the query to explicitly count distinct columns. It could look something like this: $model->deepRelation()->count('target.id')

However, I noticed this behavior when using Nova which creates the pagination automatically. And I have not yet figured out how to change that query.

@messiahUA The laravel_through_key column is required for eager loading to work.

You can only remove duplicates from the results:

$users = User::with('permissions')->get()
    ->each(function (User $user) {
        $user->setRelation('permissions', $user->permissions->unique());
    });

The opposite relationship looks like this:

class ProductItem extends Model
{
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;

    public function baseProducts()
    {
        return $this->hasManyDeep(
            BaseProduct::class,
            ['product_item_product_variant', ProductVariant::class, ProductOption::class],
            [null, null, 'id', 'id'],
            [null, null, 'product_option_id', 'base_product_id']
        );
    }
}

Relationship queries with groupBy() require additional adjustments: https://github.com/staudenmeir/eloquent-has-many-deep/issues/2#issuecomment-554963031

The (easier) alternative is removing duplicates from the query results: https://github.com/staudenmeir/eloquent-has-many-deep/issues/2#issuecomment-409006429