【问题标题】:How to filter nested collection in Laravel?如何过滤 Laravel 中的嵌套集合?
【发布时间】:2021-03-02 05:01:02
【问题描述】:

过去几个小时我一直在搜索 Stack,虽然有几个似乎相关,但似乎没有任何工作正常。

我有一个在 Laravel 上运行的 GraphQL API,并且正在尝试从 mutator 中过滤掉 current_user,这样我就不必在前端进行了。

一个用户有很多次旅行,每个旅行都通过一个名为trip_user 的数据透视表属于许多用户。在 Trip 模型上,我渴望像这样加载 Todos 和 Users 之类的东西:

Trip.php

class Trip extends Model
{
    protected $with = [
        'todos', 'shopping_list_items', 'users'
    ];

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }

    // other relationships
}

然后在将结果返回给我的 GraphQL 客户端的 TripQuery 中,我试图返回用户的所有行程,但过滤掉 current_user,如下所示:

class TripsQuery
{
    public function find_by_user($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
    {
        $user = $context->user();

        if ($user) {
            // all trip friends and todos automatically eager loaded on the model
            $trips = $user->trips()->get();

            return $trips->each->users->filter(function ($friend) use ($user) {
                return $friend->id !== $user->id;
            });
        }

        return null;
    }
}

然而,当我运行它时,它返回的 only 用户是 current_user,并且由于某种原因它返回了一个空数组 Todos,即使它应该返回其中的 4 个。我不确定为什么 ->filter() 函数不起作用(我是 Laravel 的新手,所以就是这样)。

为什么->filter 不能正常工作?

编辑 包括来自dd() 的结果:

array:2 [
  0 => array:9 [
    "id" => 1
    "name" => "Trip 1"
    "description" => "Planning for Trip 1"
    "owner_id" => 1
    "created_at" => "2020-11-18T06:28:45.000000Z"
    "updated_at" => "2020-11-18T06:28:45.000000Z"
    "todos" => array:4 [
      0 => array:6 [
        "id" => 1
        "title" => "Book car rental"
        "checked" => 0
        "trip_id" => 1
        "created_at" => "2020-11-18T17:00:46.000000Z"
        "updated_at" => "2020-11-18T17:00:46.000000Z"
      ]
      1 => array:6 [
        "id" => 2
        "title" => "Check in to flights"
        "checked" => 0
        "trip_id" => 1
        "created_at" => "2020-11-18T17:00:46.000000Z"
        "updated_at" => "2020-11-18T17:00:46.000000Z"
      ]
      2 => array:6 [
        "id" => 3
        "title" => "Drop off dog at sitter"
        "checked" => 1
        "trip_id" => 1
        "created_at" => "2020-11-18T17:00:46.000000Z"
        "updated_at" => "2020-11-18T17:00:46.000000Z"
      ]
      3 => array:6 [
        "id" => 4
        "title" => "Stop at store"
        "checked" => 1
        "trip_id" => 1
        "created_at" => "2020-11-18T17:00:46.000000Z"
        "updated_at" => "2020-11-18T17:00:46.000000Z"
      ]
    ]
    "users" => array:3 [
      0 => array:19 [
        "id" => 1
        "api_token" => null
        "email" => "test@gmail.com"
        "email_verified_at" => "2020-11-07T15:38:48.000000Z"
        "avatar_url" => null
        "created_at" => "2020-11-07T15:38:48.000000Z"
        "updated_at" => "2020-11-16T20:55:02.000000Z"
        "pivot" => array:2 [
          "trip_id" => 1
          "user_id" => 1
        ]
      ]
      1 => array:19 [
        "id" => 2
        "api_token" => null
        "email" => "michael.scott@gmail.com"
        "email_verified_at" => "2020-11-07T15:38:48.000000Z"
        "avatar_url" => null
        "created_at" => "2020-11-07T15:38:48.000000Z"
        "updated_at" => "2020-11-07T15:38:48.000000Z"
        "pivot" => array:2 [
          "trip_id" => 1
          "user_id" => 2
        ]
      ]
      2 => array:19 [
        "id" => 3
        "api_token" => null
        "email" => "pam.beasley@gmail.com"
        "email_verified_at" => "2020-11-07T15:38:48.000000Z"
        "avatar_url" => null
        "created_at" => "2020-11-07T15:38:48.000000Z"
        "updated_at" => "2020-11-07T15:38:48.000000Z"
        "pivot" => array:2 [
          "trip_id" => 1
          "user_id" => 3
        ]
      ]
    ]
  ]
  1 => array:9 [
    "id" => 2
    "name" => "Trip 2"
    "description" => "Trip 2 Description"
    "owner_id" => 1
    "created_at" => "2020-11-18T06:28:45.000000Z"
    "updated_at" => "2020-11-18T06:28:45.000000Z"
    "todos" => []
    "shopping_list_items" => []
    "users" => array:1 [
      0 => array:19 [
        "id" => 1
        "api_token" => null
        "email" => "benny.timkins@gmail.com"
        "email_verified_at" => "2020-11-07T15:38:48.000000Z"
        "avatar_url" => null
        "created_at" => "2020-11-07T15:38:48.000000Z"
        "updated_at" => "2020-11-16T20:55:02.000000Z"
        "pivot" => array:2 [
          "trip_id" => 2
          "user_id" => 1
        ]
      ]
    ]
  ]
]

【问题讨论】:

  • dd($trips->toArray()); 向您展示了什么?
  • 它给了我一个数组,其中包含我数据库中的两个测试行程
  • 请编辑您的问题以包含输出。文字,不是截图。
  • 你想在没有当前用户的情况下返回旅行吗?
  • 使用scopewhen you retrieve it 在关系级别执行此过滤会更有意义。

标签: php laravel eloquent laravel-collection


【解决方案1】:

每个都只返回当前集合用于链接机会,does not mutate the collection

从您使用GraphQL 的方式来看,我认为正确的解决方案是使用with() 方法过滤急切加载并向其添加查询。

return $user->trips()->with(['users' => function ($query) use ($user) {
    $query->where('id', '!=', $user->id);
}])->get();

为了更好的代码风格,永远不要检查条件,反转它并提前返回。

$user = $context->user();

if (! $user) {
    return null;
}

return $user->trips()->with(['users' => function ($query) use ($user) {
    $query->where('users.id', '!=', $user->id);
}])->get();

【讨论】:

  • 啊,我只是在乱用->where 函数!尝试此操作时,我收到了一个与 SQLSTATE 相关的相当大的错误:Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous (SQL: select users.*, trip_user.trip_id` as pivot_trip_id, trip_user.user_id as pivot_user_id from users inner join trip_user on users.id = trip_user.user_id 其中trip_user.trip_id 在 (1, 2) 和 id != 1)",`
  • 这消除了错误,但不幸的是它仍然保留了 current_user
  • 如何检索用户关系?如果你重新获取它们,约束将被删除
  • 我应该提到我有一个包含user_idtrip_id 列的数据透视表。当我从 Trip 中 eager_load users 时,它会将所有关联的用户拉入数据中心。
  • 但我很确定这应该可行,你如何为 api 转换你的旅行?
猜你喜欢
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 2018-04-16
  • 1970-01-01
  • 2023-01-16
相关资源
最近更新 更多