0

Okay i am working on a laravel 5.5 project.

We have a user table and in this user table we have a parent field. The parent declines the parent relationship of this object.

So each user can have 1 parent but a user can have multiple children.

    public function parent()
{
    return $this->belongsTo(User::class, 'parent_id', 'id');
}

public function children()
{
    return $this->hasMany(User::class, 'parent_id', 'id');
}

What i want to achieve is. I need to count 5 levels deep how many children a user has.

so i want something like:

Level 1: 585 Level 2: 1539 Level 3: 3294 Level 4: 4949 Level 5: 15939

Without loading the actual objects for sure, as it would kill the page performance.

How can i achieve this with laravel? Heres what i tried, but it loads all the subchildren in a collection.

  $sum = User::with('parent')->where('id','=', $user->id)->get();

Somebody can help me out with that?

EDIT:

Just to be more specific:

Lets say User A is parent of B and C

B is parent of D, E, F C has no children.

The correct output should be:

Level 1: 2 Level 2: 3 (as C has no children)

Hope that makes it more clearer

2 Answers 2

0

Sorry for responding to an old question, but i were looking to solve this issue myself and i came up with this solution which seems to work out quite well perhaps you can use it to solve your issue with this.

By eager loading the children we avoid multiple queries during the count loop, downside of always eager loading the children is if it's long and deep relationships which might return a lot of data so test it out if it performs well enough for your use case.

Some performance gains can be made by using correct indexing on your database and making sure your database is well structured, this shouldn't by any means be slow since it's a single query/done in the same query as fetching a single row.

Avoid eager loading both parent and children since they're self-referencing and will cause an infinite loop

By adding the eager load we can then loop through the relationships and return a total count of children, see the code below.

class User extends Model{
   protected $append = ['children_count'];
   protected $with = ['children']; //Eager load the relationship

   public function parent()
   {
    return $this->belongsTo(User::class, 'parent_id', 'id');
   }

   public function children()
   {
    return $this->hasMany(User::class, 'parent_id', 'id');
   } 

   public function getChildrenCountAttribute()
   {
       $count = $this->children->count(); //This specific models count

       //Loop through the already loaded children and get their count
       foreach($this->children as $child){
          $count += $child->children->count(); //Sum up the count
       }

       return $count; //Return the result
   }
}
Sign up to request clarification or add additional context in comments.

Comments

-1

what if you append a new attribute to the model

class User extends Model{
   protected $append = ['children_count'];

   public function getChildrenCountAttribute()
   {
       return $this->children()->count();
   }
}

Now you get number of a user's children without getting children

$user->children_count;

4 Comments

The Prob with that is that i will need to loop through each children and get its children count. I've seen something like User::with('children.children')->count(); but i couldnt get this working :)
Correct me if i understood you wrong. Lets take my example: $userA->children_count = 2 now when i want to access the total children count of level 2 i need to go through each user of level 1 and add the counts to have the total count.
Hmm, you're right, You need a recursive function to get total count
yep but for that i need to load each user actually which would kill page performance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.