【问题标题】:Laravel constrain eager loading - apply limit if relationship column != 1Laravel 约束急切加载 - 如果关系列应用限制!= 1
【发布时间】:2022-01-10 04:43:30
【问题描述】:

我正在构建一个与流行的名为“Anki”的抽认卡软件类似的系统,并且正在尝试加载一些属于用户研究的答案,但进行了一些修改。

模型关系

  • User 有很多 Study
  • Study 有很多 Answer

这里是代码 sn-p。 (请看下面的第二部分)

$user_query = User::with([
    'studies.answers' => function ( $query_answer ) use ( $args ) {
        $query_answer
            ->where( 'grade', '=', 'hold' )
            ->groupBy( 'card_id' )
            ->orderByDesc( 'id' );

            if ( $args['no_date_limit'] ) {
                $query_answer = $query_answer->where( 'next_due_at', '>', $args['start_date'] );
            } else {
                $query_answer = $query_answer->whereBetween( 'next_due_at', [ $args['start_date'], $args['end_date'] ] );
            }

            if ( ! empty( $args['card_ids_in'] ) ) {
                $query_answer = $query_answer->whereIn( 'card_id', $args['card_ids_in'] );
            }
            if ( ! empty( $args['card_ids_not_in'] ) ) {
                $query_answer = $query_answer->whereNotIn( 'card_id', $args['card_ids_not_in'] );
            }

下面,如果study.answer_all_on_hold ($study_all_on_hold) != 1,我想应用限制 并从study.no_on_hold读取$no_on_hold

            // Here, I want to apply the limit ($study_all_on_hold ) if study.answer_all_on_hold != 1
            if ( ! $study_all_on_hold ) {
                // And also read the $no_on_hold value from study.no_on_hold
                $query_answer = $query_answer->limit( $no_on_hold );
            }
        },
    ])
    ->where( 'ID', '=', $user_id );

如您所见,我正在尝试应用研究列值的限制。 目前可以吗?

编辑

我已经通过阅读研究study.no_on_hold 中的列的值来了解如何添加限制。剩下的就是仅在 study.answer_all_on_hold 为 != 1 时应用该限制的方法

//if ( ! $study_all_on_hold ) {
            $query_answer = $query_answer->limit( 'study.no_on_hold' );
//  }

【问题讨论】:

  • 可能不在单个查询中。不过,您绝对可以映射生成的集合以获得您想要的格式。
  • 感谢您的建议,但我真的需要在应用所有这些条件的情况下急切地加载答案。我试过单独加载它,同时循环研究,但运行了很多查询,这就是为什么我对预先加载进行排序。
  • 没有办法做到这一点,即使在原始 SQL 中也是如此。此外,您应该使用when() 方法查看条件查询子句,这将使您的代码更加简洁。

标签: laravel laravel-5 eloquent laravel-query-builder


【解决方案1】:

在您的示例中,Eloquent 正在执行 3 个查询:

  1. SELECT * FROM users WHERE id = $user_id
  2. SELECT * FROM studies WHERE user_id IN (all users.id from query 1)
  3. SELECT * FROM answers WHERE study_id IN (all studies.id FROM query 2)

然后,它将所有结果分组到生成的Collection 中。由于 Eloquent 的工作方式,您不能在查询 3 上添加 LIMIT

我认为你可以通过应用一些collection methods 来获得你想要的结果。

$user_query = User::...get();

$user_query = $user_query->each(function ($user) {
    $user->studies->transform(function ($study) {
        if ($study->answer_all_on_hold != 1) {
            $study->answers = $study->answers->take($study->no_on_hold)->values();
            return $study;
        } else {
            return $study;
        }
    });
});

这不会改变查询(因此您仍然会查询每个答案),甚至会导致一些额外的开销。

【讨论】:

  • 感谢您的回答。我真的不想做任何循环,因为随着用户开始使用该系统,会有很多研究。同样调用 $user->studies 将执行另一个查询,$study->answers 也将执行(将为每个研究执行)。不是吗?
  • 我已经通过 $query_answer = $query_answer->limit( 'study.no_on_hold' ); 弄清楚了如何应用限制.剩下的唯一事情是如何仅在 study.answer_all_on_hold 为 =1 时应用该限制(当它为真时)
  • 执行$query_answer->limit('study.no_on_hold') 将对每个答案产生影响。不只是属于特定的Study
  • 要明白我的意思,请尝试输入limit(1),您会发现您将在 3 项研究中得到一个答案,即使所有研究都至少有一个答案。
  • $query_answer->limit('study.no_on_hold') 将我将为每个Study 阅读的答案数量限制为每个study.no_on_hold 的值,这就是我需要的。这就是为什么我不能使用硬值作为限制,比如limit(1)。它目前对我很有用,只是只有当每个研究的 study.answer_all_on_hold 的列值为 != 1 时,我才需要应用该限制
猜你喜欢
  • 2013-12-25
  • 1970-01-01
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-29
  • 2016-02-09
相关资源
最近更新 更多