如何合并两个 Eloquent 集合?
Posted
技术标签:
【中文标题】如何合并两个 Eloquent 集合?【英文标题】:How to Merge Two Eloquent Collections? 【发布时间】:2015-08-11 21:41:41 【问题描述】:我有一个问题表和一个标签表。我想从给定问题的标签中获取所有问题。因此,例如,我可能将标签“旅行”、“火车”和“文化”附加到给定问题上。我希望能够获取这三个标签的所有问题。看起来棘手的是问题和标签关系是在 Eloquent 中定义为 belongsToMany 的多对多关系。
我想过尝试合并问题集合如下:
foreach ($question->tags as $tag)
if (!isset($related))
$related = $tag->questions;
else
$related->merge($tag->questions);
但它似乎不起作用。似乎没有合并任何东西。我是否正确地尝试了这个?另外,在 Eloquent 中是否有更好的方法来获取多对多关系中的一行行?
【问题讨论】:
您是否查看过有关预加载和 with 方法的文档?使用更好的 eloquent 查询可以轻松解决您的问题。一旦我掌握了计算机,我就会写一个例子,除非有人打败了我。 @Luceoswith
无济于事。需要whereHas
- 就像下面的答案一样。
是的,我的错;你是对的
【参考方案1】:
Collection
上的 merge()
方法不会修改调用它的集合。它返回一个包含新数据的新集合。您需要:
$related = $related->merge($tag->questions);
但是,我认为您从错误的角度解决问题。
由于您要查找符合特定条件的问题,因此以这种方式查询可能会更容易。 has()
和 whereHas()
方法用于根据相关记录的存在生成查询。
如果您只是在寻找带有任何标签的问题,您可以使用has()
方法。由于您要查找带有特定标签的问题,因此您可以使用 whereHas()
添加条件。
因此,如果您希望所有问题至少有一个带有“Travel”、“Trains”或“Culture”的标签,您的查询将如下所示:
$questions = Question::whereHas('tags', function($q)
$q->whereIn('name', ['Travel', 'Trains', 'Culture']);
)->get();
如果您想要包含所有这三个标签的所有问题,您的查询将如下所示:
$questions = Question::whereHas('tags', function($q)
$q->where('name', 'Travel');
)->whereHas('tags', function($q)
$q->where('name', 'Trains');
)->whereHas('tags', function($q)
$q->where('name', 'Culture');
)->get();
【讨论】:
+,但是您建议的第二个(所有标签)选项可能会被简化:***.com/a/24706347/784588 但您不能对标签名称进行硬编码。在这个例子中,问题恰好有这些标签,但在其他问题中,标签会有所不同【参考方案2】:merge 方法返回合并后的集合,它不会改变原始集合,因此您需要执行以下操作
$original = new Collection(['foo']);
$latest = new Collection(['bar']);
$merged = $original->merge($latest); // Contains foo and bar.
将示例应用到您的代码中
$related = new Collection();
foreach ($question->tags as $tag)
$related = $related->merge($tag->questions);
【讨论】:
我试图从树中构建一个平面列表,使用 push 是我所需要的,但 foreach 方法确实有帮助。 请记住,Eloquent 集合的行为与普通集合不同,即。他们使用getKey
来合并结果,所以Model::all()->merge(Model::all())->count() === Model::all()->count()
请注意,如果提供的 $items 中存在具有相同值的字符串键,则合并方法将替换原始第二个集合的项目中的任何第一个集合。如果第一个集合键是数字,则第二个集合将添加到新集合的末尾laravel.com/docs/8.x/collections#method-merge【参考方案3】:
将两个不同的 eloquent 集合合并为一个,一些对象碰巧有相同的 id,一个会覆盖另一个。改用 push() 方法或重新考虑解决问题的方法以避免这种情况。 Refer to web
【讨论】:
谢谢,这让我看到了medium.com/@jeffparr_57441/… 此处的评论,这似乎干净利落地完成了这项工作而不会被覆盖。 使用 ->push() 更安全【参考方案4】:$users = User::all();
$associates = Associate::all();
$userAndAssociate = $users->merge($associates);
【讨论】:
阅读(覆盖):medium.com/@tadaspaplauskas/… @Jeffz 仅凭 ID 就合并“重复项”真是令人难以置信【参考方案5】:eloquent collections 都不适合我,laravel eloquent collections 使用 我认为 导致合并问题的项目中的密钥,您需要获取第一个集合作为一个数组返回,将其放入一个新的集合中,然后将其他的推入新的集合中;
public function getFixturesAttribute()
$fixtures = collect( $this->homeFixtures->all() );
$this->awayFixtures->each( function( $fixture ) use ( $fixtures )
$fixtures->push( $fixture );
);
return $fixtures;
【讨论】:
【参考方案6】:为每个 eloquent 集合创建一个新的基础集合,合并对我有用。
$foo = collect(Foo::all());
$bar = collect(Bar::all());
$merged = $foo->merge($bar);
在这种情况下,它的主键没有冲突。
【讨论】:
【参考方案7】:我想补充一点,我发现 concat 方法似乎没有基于 ID 覆盖,而 merge 方法可以。 concat 似乎对我有用,而 merge 引起了问题。
【讨论】:
【参考方案8】:我在使用合并时遇到了一些问题。所以我使用了concat。你可以像下面这样使用它。
$users = User::all();
$associates = Associate::all();
$userAndAssociate = $users->concat($associates);
【讨论】:
以上是关于如何合并两个 Eloquent 集合?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Laravel 4 中手动创建一个新的空 Eloquent 集合
如何从 laravel 的 eloquent 集合中获取外键