113

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

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

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

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

4

9 回答 9

172

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);
}
于 2015-05-29T07:54:03.157 回答
40

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

$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();
于 2015-05-29T06:53:48.463 回答
30
$users = User::all();
$associates = Associate::all();

$userAndAssociate = $users->merge($associates);
于 2018-02-14T11:49:18.493 回答
17

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

于 2017-12-19T23:16:29.107 回答
11

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

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

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

于 2020-03-23T17:59:00.600 回答
1

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

public function getFixturesAttribute()
{
    $fixtures = collect( $this->homeFixtures->all() );
    $this->awayFixtures->each( function( $fixture ) use ( $fixtures ) {
        $fixtures->push( $fixture );
    });
    return $fixtures;
}
于 2018-04-20T11:59:57.423 回答
0

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

于 2021-12-13T10:19:08.080 回答
0

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

$users = User::all();
$associates = Associate::all();
$userAndAssociate = $users->concat($associates);
于 2021-12-21T06:05:57.230 回答
0

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

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

/** $foo will contain $foo + $bar */
$foo->push(...$bar);
于 2022-02-16T13:41:17.770 回答