ChatGPT解决这个技术问题 Extra ChatGPT

如何合并两个 Eloquent 集合?

我有一个问题表和一个标签表。我想从给定问题的标签中获取所有问题。因此,例如,我可能会将标签“旅行”、“火车”和“文化”附加到给定问题上。我希望能够获取这三个标签的所有问题。看起来棘手的是问题和标签关系是在 Eloquent 中定义为 belongsToMany 的多对多关系。

我考虑过尝试合并问题集合如下:

foreach ($question->tags as $tag) {
    if (!isset($related)) {
        $related = $tag->questions;
    } else {
        $related->merge($tag->questions);
    }
}

但它似乎不起作用。似乎没有合并任何东西。我是否正确地尝试了这个?另外,在 Eloquent 中是否有更好的方法来获取多对多关系中的一行行?

您是否查看过有关预加载和 with 方法的文档?使用更好的 eloquent 查询可以轻松解决您的问题。一旦我掌握了计算机,我就会写一个例子,除非有人打败了我。
@Luceos with 无济于事。需要的是 whereHas - 就像下面的答案一样。
是的,我的错;你是对的

W
Wader

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 的末尾
我认为需要删除重复项。
p
patricus

Collection 上的 merge() 方法不会修改调用它的集合。它返回一个新集合,其中合并了新数据。您需要:

$related = $related->merge($tag->questions);

但是,我认为您从错误的角度解决了这个问题。

由于您正在寻找符合特定标准的问题,因此以这种方式查询可能会更容易。 has()whereHas() 方法用于根据相关记录的存在生成查询。

如果您只是在寻找带有任何标签的问题,您可以使用 has() 方法。由于您要查找带有特定标签的问题,因此您可以使用 whereHas() 添加条件。

因此,如果您想要所有至少有一个带有“旅行”、“火车”或“文化”标签的问题,您的查询将如下所示:

$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();

+,但是您建议的第二个(所有标签)选项可能会被简化:stackoverflow.com/a/24706347/784588
但是您不能对标签名称进行硬编码。在这个例子中,问题恰好有这些标签,但在其他问题中,标签会有所不同
s
sh6210
$users = User::all();
$associates = Associate::all();

$userAndAssociate = $users->merge($associates);

阅读此内容(覆盖):medium.com/@tadaspaplauskas/…
@Jeffz 仅基于 ID 合并“重复项”真是令人难以置信
n
newbie2005

将两个不同的 eloquent 集合合并为一个,一些对象恰好具有相同的 id,一个会覆盖另一个。请改用 push() 方法或重新考虑解决问题的方法以避免这种情况。 Refer to web


谢谢,这让我在此处找到的评论 medium.com/@jeffparr_57441/… 似乎干净地完成了这项工作而没有覆盖。
使用 ->push() 更安全
J
João Carlos Junior

为每个雄辩的集合创建一个新的基础集合,合并对我有用。

$foo = collect(Foo::all());
$bar = collect(Bar::all());
$merged = $foo->merge($bar);

在这种情况下,它的主键没有冲突。


M
Miraj Khandaker

我使用合并遇到了一些问题。所以我使用了concat。你可以像下面这样使用它。

$users = User::all();
$associates = Associate::all();
$userAndAssociate = $users->concat($associates);

L
Luke Snowden

所有这些都不适用于 eloquent 集合,laravel eloquent 集合使用我认为会导致合并问题的项目中的密钥,您需要将第一个集合作为数组取回,将其放入新集合中,然后将其他集合推入新系列;

public function getFixturesAttribute()
{
    $fixtures = collect( $this->homeFixtures->all() );
    $this->awayFixtures->each( function( $fixture ) use ( $fixtures ) {
        $fixtures->push( $fixture );
    });
    return $fixtures;
}

t
trckster

对此我很抱歉,但从 PHP 7.4 开始,您可以这样做(最好使用 merge)。

$foo = Foo::all();
$bar = Bar::all();

/** $foo will contain $foo + $bar */
$foo->push(...$bar);

A
AidenFry

我想补充一点,我发现 concat 方法似乎没有基于 ID 覆盖,而 merge 方法可以。 concat 似乎对我有用,而 merge 引起了问题。