首页 > 解决方案 > Laravel 5.6 - 使用 Eloquent 在相关表的日期时间字段中返回最新日期的问题

问题描述

我有两个表:患者和 appts(约会)。有一个一对多的关系患者:appt。我的目标是返回一组患者,并从关系中返回患者上次和下次约会的日期。

问题/问题

我得到不一致的结果。我已经播种了数据,以便每个患者在过去和将来都有约会,但是当我使用 Eloquent 进行查询时(请参阅下面的“控制器”),我没有得到“lastappt”。如果我修改查询以按患者 ID 进行搜索,我会得到最后一个应用程序。

“病人”模型

class Patient extends Model
{
    ...
    public function appts()
    {
        return $this->hasMany('App\Models\Appt');
    }
    public function lastappt()
    {
        $now = Carbon::now();
        return $this
            ->hasMany('App\Models\Appt')
            ->select(['id', 'patient_id', 'appt_date_time'])
            ->where('appt_date_time', '<', $now)
            ->orderBy('appt_date_time', 'desc')
            ->take(1);
    }
    public function nextappt()
    {
        $now = Carbon::now();
        return $this
            ->hasMany('App\Models\Appt')
            ->select(['id', 'patient_id', 'appt_date_time'])
            ->where('appt_date_time', '>', $now)
            ->orderBy('appt_date_time', 'asc')
            ->take(1);
    }
}    

“Appts”迁移

Schema::create('appts', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('patient_id')->unsigned();
    $table->integer('hospital_id')->unsigned();
    ...
    $table->datetime('appt_date_time')->nullable();
    ...
    $table->timestamps();
    $table->index(['patient_id', 'hospital_id', 'appt_date_time']);
    $table->foreign('patient_id')
        ->references('id')->on('patients')
        ->onDelete('cascade');
});

控制器

$currPatientCollection = Patient::with('lastappt')
    ->with('nextappt')
    ->where('office_id', $user->office_id)
    ->where('current_patient', true)
    ->orderBy('last_name')
    ->orderBy('first_name')
    ->get();

这仅返回一个 nextappt,即使数据库过去有 appts。但是,以下查询有效(正如我“预期的”),并返回带有 lastappt 和 nextappt 的患者记录。

$currPatientCollection = Patient::with('lastappt')
    ->with('nextappt')
    ->where('id', 1)
    ->where('current_patient', true)
    ->orderBy('last_name')
    ->orderBy('first_name')
    ->get();

任何帮助将不胜感激,并提前感谢您!

标签: phplaravellaravel-5eloquentlaravel-5.6

解决方案


您可以使用:

public function lastappt()
{
    $now = Carbon::now();
    return $this
        ->hasOne('App\Models\Appt')
        ->select(['id', 'patient_id', 'appt_date_time'])
        ->where('appt_date_time', '<', $now->toDateTimeString())
        ->orderBy('appt_date_time', 'desc')
        ->groupBy('patient_id');
}

public function nextappt()
{
    $now = Carbon::now();
    return $this
        ->hasOne('App\Models\Appt')
        ->select(['id', 'patient_id', 'appt_date_time'])
        ->where('appt_date_time', '>', $now->toDateTimeString())
        ->orderBy('appt_date_time', 'asc')
        ->groupBy('patient_id');
}

现在您可以使用:

$patient = Patient::find($someId);
echo $patient->lastappt->appt_date_time;
echo $patient->nextappt->appt_date_time;

当然,在上面的 3 行中,您应该假设lastapptnextappt可能为 null,以便您可以使用optionalhelper:

echo optional($patient->lastappt)->appt_date_time;
echo optional($patient->nextappt)->appt_date_time;

当然,当您有多个患者时,您应该急切地加载这些关系以避免 n+1 查询问题:

$patients = Patient::with('lastappt', 'nextappt')->whereIn('id', $someIds)->get();

推荐阅读