如何通过Baum/Node获取多个ID的分类子节点?
解决多个分类ID获取子节点的问题
你说得一点没错——->get()返回的是Eloquent集合,而getDescendants()是Baum/Node单个模型实例才有的方法,直接在集合上调用肯定会报错。下面给你两种可行的解决方案,你可以根据实际场景选择:
方案1:循环遍历每个模型(直观易实现)
这就是你一开始想到的思路,直接循环每个分类模型,分别调用getDescendants()后合并结果:
$targetIds = [41, 94]; $allDescendantIds = collect(); // 遍历每个分类模型 foreach (\App\Categories::whereIn('id', $targetIds)->get() as $category) { // 合并当前分类的所有子节点ID $allDescendantIds = $allDescendantIds->merge($category->getDescendants()->pluck('id')); } // 可选:如果不同分类的子节点可能有重复ID,去重并重置索引 return $allDescendantIds->unique()->values();
这种方法的优点是简单直观,不用纠结嵌套集的底层逻辑;缺点是如果目标ID数量较多,会触发多次数据库查询,性能会打折扣。如果你的业务中目标ID数量很少,完全可以用这种方式。
方案2:利用嵌套集特性直接查询数据库(性能更优)
Baum的嵌套集依赖lft(左值)和rgt(右值)字段来维护层级关系:某个节点的所有子节点,其lft值一定在父节点的lft和rgt之间。我们可以利用这个特性,直接写查询来一次性获取所有子节点:
// 先获取目标分类的lft和rgt范围 $parentCategories = \App\Categories::whereIn('id', [41, 94])->get(['lft', 'rgt']); // 查询所有在这些lft/rgt范围内的子节点 $descendantIds = \App\Categories::where(function ($query) use ($parentCategories) { foreach ($parentCategories as $category) { // lft+1和rgt-1是为了排除父节点本身,如果你需要包含父节点就去掉±1 $query->orWhereBetween('lft', [$category->lft + 1, $category->rgt - 1]); } })->pluck('id'); return $descendantIds;
这种方法只需要两次数据库查询,不管目标ID有多少,性能都很稳定,适合ID数量较多的场景。
关于循环方案的合理性
循环每个ID调用getDescendants()是完全可行的,属于“简单场景下的推荐做法”——如果你的业务中不需要处理大量ID,这种写法清晰易懂,后期维护也方便。只有当ID数量较多(比如几十上百个)时,才需要考虑换成方案2来优化性能。
内容的提问来源于stack exchange,提问作者Galivan
相关产品推荐
相关产品推荐

