How to implement a graph of nodes without duplicate descendants? #237
-
I'm not sure if the title is clear, but essentially I have a structure with a single table containing Nodes, where each Node (through a pivot table I set this up just fine, using a model like so: use Staudenmeir\LaravelAdjacencyList\Eloquent\HasGraphRelationships;
class Node extends Model
{
use HasGraphRelationships;
// Override methods for custom table/column names here
} This seems to work, but I don't get the output I expect. Say I have 1 root Node, with 36 direct children. Each of these 36 children are parents to the same 1 grandchild Node. In this case, I'd expect My understanding of why this occurs is that the One workaround I could potentially implement would look like this: $ids = $node->descendants()->getQuery()->select('nodes.id')->distinct()->get()->pluck('id');
$descendants = Node::whereIn('id', $ids)->get(); I get the feeling I'm misunderstanding a concept in how to use this package, and I'd like to avoid using this workaround as performance is important, and I need to do it in many places throughout the application. As per the above issue, I understand that this behaviour won't be implemented as default, as it's a breaking change, but would it be possible to add an option to the relationship methods to support this? Simply chaining Thanks for your time and help in advance. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
Hi @bluesheep100,
The descendants query traverses the graph to discover all possible paths and return the nodes it finds on the way. The grandchild node is returned 36 times because 36 different paths lead to it. Each query result is a "combination" of a node and a path leading to it (represented by the From the other issue:
If your pivot table contains additional columns, the different grandchild query results have different pivot values depending on the path.
The current behavior is the default because it's the SQL query's "natural" behavior (it's also the most useful behavior for the applications that I know). Removing "duplicate" nodes can only be an additional step on top of that.
I've looked into this topic quite a bit because it's also relevant for another one of my packages, but it's quite the nightmare.
That's exactly the reason why the whole topic is so complicated. A general solution also needs to work with eager loading etc. |
Beta Was this translation helpful? Give feedback.
-
The easiest solution is removing duplicates from the result collection: $uniqueDescendants = $node->descendants->unique();
Are you having performance issues? |
Beta Was this translation helpful? Give feedback.
Hi @bluesheep100,
The descendants query traverses the graph to discover all possible paths and return the nodes it finds on the way. The grandchild node is returned 36 times because 36 different paths lead to it. Each query result is a "combination" of a node and a path leading to it (represented by the
depth
andpath
attributes).From the other issue:
If your pivot table contains additional columns, the different grandchild query results have different piv…