如何在Laravel中有效地改变预加载数据的结构

如何在Laravel中有效地改变预加载数据的结构,laravel,eloquent,Laravel,Eloquent,我急切地在Laravel中加载一个产品的关系数据 $product = Product::with('attributeValues.attribute')->find($id)->get(); 目前我得到的响应结构如下 [ { "product_id": 1, "product_name": "Shirt A", "attribute_values&quo

我急切地在Laravel中加载一个产品的关系数据

$product = Product::with('attributeValues.attribute')->find($id)->get();
目前我得到的响应结构如下

[
    {
        "product_id": 1,
        "product_name": "Shirt A",
        "attribute_values": [
            {
                "attribute_value_id": 1,
                "attribute_value": "small",
                "attribute": {
                    "attribute_id": 1,
                    "attribute": "size"
                }
            },
            {
                "attribute_value_id": 1,
                "attribute_value": "medium",
                "attribute": {
                    "attribute_id": 1,
                    "attribute": "size"
                }
            },
            ...
        ]
    },
    ...
]
[
    {
        "product_id": 1,
        "product_name": "Shirt A",
        "attribute": [
            {
                "attribute_id": 1,
                "attribute": "size",
                "attribute_values": [
                    {
                        "attribute_value_id": 1,
                        "attribute_value": "small"
                    },
                    {
                        "attribute_value_id": 1,
                        "attribute_value": "medium"
                    }
                ]
            },
            ...
        ]
    },
    ...
]
我希望得到的结构如下

[
    {
        "product_id": 1,
        "product_name": "Shirt A",
        "attribute_values": [
            {
                "attribute_value_id": 1,
                "attribute_value": "small",
                "attribute": {
                    "attribute_id": 1,
                    "attribute": "size"
                }
            },
            {
                "attribute_value_id": 1,
                "attribute_value": "medium",
                "attribute": {
                    "attribute_id": 1,
                    "attribute": "size"
                }
            },
            ...
        ]
    },
    ...
]
[
    {
        "product_id": 1,
        "product_name": "Shirt A",
        "attribute": [
            {
                "attribute_id": 1,
                "attribute": "size",
                "attribute_values": [
                    {
                        "attribute_value_id": 1,
                        "attribute_value": "small"
                    },
                    {
                        "attribute_value_id": 1,
                        "attribute_value": "medium"
                    }
                ]
            },
            ...
        ]
    },
    ...
]
模型的当前关系如下所示

class Product extends Model {
    public function attributeValues(){
        return $this->belongsToMany(AttributeValue::class, 'product_attributes');
    }
}

class AttributeValue extends Model {
    public function attribute(){
        return $this->belongsTo(Attribute::class);
    }
}

class Attribute extends Model { }
目前,通过使用产品和使用原始查询分别获取其属性,我成功地获得了正确的结构。我正试图以一种雄辩的方式完成这项任务

我的表格如下

class Product extends Model {
    public function attributeValues(){
        return $this->belongsToMany(AttributeValue::class, 'product_attributes');
    }
}

class AttributeValue extends Model {
    public function attribute(){
        return $this->belongsTo(Attribute::class);
    }
}

class Attribute extends Model { }
产品

产品属性

属性值

属性

最好的方法是使用JsonResource

只需定义ProductResource、attribyteValueResource和AttributeResource

以下是一个例子:

物业资源:

AttributeValue资源:

属性来源:

那就用它们吧:

$product = ProductResource::make(
    Product::load('attributeValues.attribute')->find($id)
);
最好的方法是使用JsonResource

只需定义ProductResource、attribyteValueResource和AttributeResource

以下是一个例子:

物业资源:

AttributeValue资源:

属性来源:

那就用它们吧:

$product = ProductResource::make(
    Product::load('attributeValues.attribute')->find($id)
);
那使用什么呢?我不是专家,但我会这样做:

$products->map(function($product){

  $attribute = $product->attribute_values->groupBy('attribute.attribute')->map(function($groupAttribute,$key){
    $attribute_values = $groupAttribute->map(function($attribute) {
        return ['attribute_value_id'=>$attribute->attribute_value_id,'attribute_value'=>$attribute->attribute_value];
    });
    return ['attribute_id' => 1 ,'attribute'=> $key , 'attribute_values' => $attribute_values  ];
  });

  return [
          'product_id'=>$product->product_id,
          'product_name'=>$product->product_name,
          'attribute'=>$attribute
        ];
});

那使用什么呢?我不是专家,但我会这样做:

$products->map(function($product){

  $attribute = $product->attribute_values->groupBy('attribute.attribute')->map(function($groupAttribute,$key){
    $attribute_values = $groupAttribute->map(function($attribute) {
        return ['attribute_value_id'=>$attribute->attribute_value_id,'attribute_value'=>$attribute->attribute_value];
    });
    return ['attribute_id' => 1 ,'attribute'=> $key , 'attribute_values' => $attribute_values  ];
  });

  return [
          'product_id'=>$product->product_id,
          'product_name'=>$product->product_name,
          'attribute'=>$attribute
        ];
});


只需执行以下操作,即可获得所需的结果

$product = Product::with('attribute.attributeValues')->find($id)->get();

只需执行以下操作,即可获得所需的结果

$product = Product::with('attribute.attributeValues')->find($id)->get();
您可以通过以下方式与inside一起使用:

您可以通过以下方式与inside一起使用:


这种方法的性能如何?我的意思是,有很多查询使用资源在后台运行,它的工作没有N+1问题,因为$this->whenLoaded方法正在使用,这种方法的性能如何?我的意思是,有很多查询是在后台使用资源运行的,它不会出现N+1问题,因为$this->whenLoaded方法正在使用
$product = Product::with('attribute.attributeValues')->find($id)->get();
  $product = Product::with(['attributeValues'=>function($query){
            $query->select(['attribute_value_id','attribute_value'])
                ->with('attribute:attribute_id,attribute');
        }])->find($id)->get();