首页 > 解决方案 > Laravel 过滤 hasMany 关系

问题描述

首先是我的问题的背景。用户 hasManycontactscontacthasMany anniversaries。我想过滤即将到来的周年纪念日。到目前为止,我有这个:

$filtered = auth()->user()->contacts()->get()->each(function ($contact) {
    $contact->anniversaries->filter(function ($anniversary) {

        // return true or false based on a method on the anniversary model
        return $anniversary->method() == true;

    });
});

但这只是返回所有联系人(显然)及其所有周年纪念日,我希望排除那些在调用$anniversary->method().

无论在什么$anniversary->method()都不重要,这只是返回一个trueor false

当我执行以下操作时,它会起作用:

$collection = auth()->user()->anniversaries()->get();

$filtered = $collection->filter(function ($anniversary) {
    return $anniversary->method() == true;
});

我只得到$anniversary->method()确实存在的周年纪念日true

我的问题主要是,为什么会发生这种情况,我只想了解它,而不是需要如何使其工作的答案。提前感谢您的任何见解!

标签: phplaravelfilter

解决方案


在第一个示例中,您只过滤anniversaries每个联系人的。您没有contacts直接按看到过滤。

$filtered = auth()->user()->contacts()->get()->each(function ($contact) {
    // You are filtering only the anniversaries of each contact
    $anniversaries = $contact->anniversaries->filter(function ($anniversary) {
        return $anniversary->method() == true;

    });

    // over here you should get the same as in your second example
    dd($anniversaries);
});

在您的第二个示例中,您正在执行以下伪代码:

  1. 获取每个用户的所有周年纪念日
  2. 筛选匹配的周年纪念日$anniversary->method() === true

要在第一个示例中获得相同的结果,您必须使用filterwith的组合->count()

$filtered = auth()->user()->contacts()->get()->filter(function ($contact) {
    $filteredByMethod = $contact->anniversaries->filter(function ($anniversary) {

        // return true or false based on a method on the anniversary model
        return $anniversary->method() == true;
    });

    return $filteredByMethod->count() > 0;
});

哪个性能更高超出了此答案的范围。

小建议

filterfrom方法Laravel's collections需要返回一个truthy要过滤的值。由于您的method回报true or false,您可以直接调用该方法而无需与true

$collection = auth()->user()->anniversaries()->get();

$filtered = $collection->filter(function ($anniversary) {
    return $anniversary->method();
});

推荐阅读