根据 Laravel 中的透视值检索每个关系 1 个透视行属于 ToMany 关系



>背景- 我正在创建一个系统,管理员可以在其中创建任意字段,然后将其组合成一个表单。然后,用户填写此表单,针对每个字段输入的值将存储在表中。但是,我计划将每个过去的值保留为表中的单独行,而不是覆盖以前的值。然后,我希望能够显示每个表单中提交的内容,但仅显示最近提交的值。

问题

我有一个模型,Service,它与另一个模型Field具有属于许多关系。此关系定义为:

public function fields()
{
return $this->belongsToMany('AppField')->withPivot('id', 'value', 'date')->withTimestamps();
}

中间表有 3 个我希望检索的值,idvaluedate

一个Service可以有 1 个或多个Fields,对于每个字段,它还可能具有 1 个以上的透视行。也就是说,单个Service/Field配对在数据透视表中可能有多个具有不同数据透视值的条目。例如:

表field_service

id      | service_id | field_id | value   | created_at
------------------------------------------------------
1       | 1          | 1        | lorem   | 2018-02-01
2       | 1          | 1        | ipsum   | 2018-01-01
3       | 1          | 1        | dolor   | 2017-12-01
4       | 1          | 2        | est     | 2018-03-10
5       | 1          | 2        | sicum   | 2018-03-09
6       | 1          | 2        | hoci    | 2018-03-08

我想要的是得到:

  • 数据透视表中与Service关联的每个Field的特定行,或
  • 数据透视表中与Service关联的每个Field的特定value

例如 - 在上表中,我希望 ID 为 1 的Service在关系中具有 2 个Field,每个Field都包含相应枢轴值的属性。附加Fields将由具有最新日期的相应数据透视表条目指定。类似于:

$service->fields()[0]->value = "lorem"
$service->fields()[1]->value = "est"

我觉得有一个明显的,'拉拉维尔'的解决方案,但它躲开了我......

更新

有点令人难以置信的是,这是我不理解窗口函数的另一个情况。7年前我问了一个问题,基本上就是这个问题,但使用原始MySQL。下面的原始MySQL基本上给了我想要的东西,我只是不知道如何拉拉维化它:

SELECT services.name, fields.name, field_service.value, field_service.created_at, field_service.field_id
FROM field_service
INNER JOIN 
(SELECT field_id, max(created_at) as ts
FROM field_service
WHERE service_id = X
GROUP BY field_id) maxt
ON (field_service.field_id = maxt.field_id and field_service.created_at = maxt.ts)
JOIN fields ON fields.id = field_service.field_id
JOIN services ON services.id = field_service.service_id

试试这个:

public function fields()
{
$join = DB::table('field_service')
->select('field_id')->selectRaw('max(`created_at`) as `ts`')
->where('service_id', DB::raw($this->id))->groupBy('field_id');
$sql = '(' . $join->toSql() . ') `maxt`';
return $this->belongsToMany(Field::class)->withPivot('id', 'value', 'created_at')
->join(DB::raw($sql), function($join) {
$join->on('field_service.field_id', '=', 'maxt.field_id')
->on('field_service.created_at', '=', 'maxt.ts');
});
}

然后像这样使用它:

$service->fields[0]->pivot->value // "lorem"
$service->fields[1]->pivot->value // "est"

最新更新