-
Notifications
You must be signed in to change notification settings - Fork 459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Eager loading children #45
Comments
i suspect the extra queries you are seeing may be related to something i discovered when creating my #46 pull request. thinking about it a more general solution would be to adjust the children function of Node to return an empty collection if isLeaf() returns true as there are of course no children!. |
Thanks -- that definitely sounds like a solution. I'll try your branch. But what I'd really like to do is eager load a whole tree (or subtree) without using toHierarchy at all. |
Your fixes took queries on one page down from 35 to 7. I'll be using my own tremby/baum#patched branch which has your fixes and mine until @etrepat looks in. |
i don't follow... if you retrieve "all" nodes you are interested in and then run toHierarchy you have all nested children that you will need....
with
you could restrict it using where's etc to only the ones you want rather than all.
becomes
and your last part shouldn't need changing. there is still a problem with toHierarchy not eager loading "all" children if you were filtering the initial query somehow but i think that is probably a good thing incase you are using the children of one of the retrieved nodes outside of the initial context. |
Well the thing which bothers me about toHierarchy is that it is called on a Node, but returns a Collection with one child which is the Node it was called on. That just seems very confusing to me -- why the outer Collection? So I need to do this:
which is kind of obtuse, and if that were someone else's code I was reading I would worry that the ->first() call might be throwing away potential other child nodes. I've also had a few related issues with I just tried But why can't I do this instead?
and then be able to use the same existing $menuItem object and walk its tree, all already preloaded? |
i think you may be misunderstanding... so the idea is that you grab a collection that includes all of the nodes you want (including children), as a simple one dimensional array of objects then run the toHierarchy method to iterate over that collection nesting the objects as appropriate. so
first gets all the menu items and then turns it into a hierarchy. the result will be a collection containing just your root nodes with all of their descendants nested (and pre-loaded) beneath them. if you only wanted one particular tree or subtree you would just select that node then use
where $node is a specific node that you have grabbed from any sort of query you like. |
Okay, so there's something I'm not getting about the relationship between Builder objects and Eloquent objects. If I do But if I try to run So when faced with a Builder object I know I need to run So I'm with you now. And I figured out why the number of queries running was the same for me whether I ran So what I want, it seems, is a shortcut, to go from a Node object directly to that same Node object with all children eager loaded. So I've written myself this:
and put it in my Node, and it seems to work well. It seems to me that it'd be useful in core, so I'll make a PR. |
Actually, I've found that though the above function works, it is not modifying the object but returning another. So if I do $menuItem->loadChildren()->walkThroughTree(); ...I get just the one query and it works as expected, but if I do $menuItem->loadChildren();
$menuItem->walkThroughTree(); the eager-loading hasn't stuck and it runs more queries. That doesn't seem ideal. Any thoughts? |
Load children returns an altered copy of the menuitem object it does not alter the original object it was called on.
Would work. |
Yes, I'm aware of the differences and why each works the way it does. I was trying to highlight the shortcoming, rather than ask what I was doing wrong. I was more asking for comment on a possible solution -- whether it's possible or not (and how) to have this |
Well in that case i would change getChildren to something like
Should do the trick.
|
That's perfect. Thanks. That ought to be available on Node by default. |
Closing in favour of pull request. |
How do I eager load all a model's descendants? I'm traversing the tree from a given node and every time I ask for a node's children it's sending out another database query. They're really adding up.
I'm using toHierarchy in a different area of my code which already seems very awkward since I have to get a single Node model, then call the method, and now I've got a collection I need to get the first element of again. I can live with that, though I'd prefer to just start with the Node and be able to grab children without a new query actually being made, having already preloaded all children. But anyway, when I traverse through the Collection toHierarchy gave me I still get new database queries getting fired off.
In that case I'm doing
The view has
The children partial view has
The item partial view prints an
<li>
in which the children partial is called again recursively on $model. There are more and more queries being fired off.The text was updated successfully, but these errors were encountered: