【问题标题】:Laravel Eloquent perform Aggregation function in the pivot relationshipLaravel Eloquent 在枢轴关系中执行聚合功能
【发布时间】:2021-07-24 12:49:26
【问题描述】:

我想对存储在名为“评论”的数据透视表中的各个产品进行平均评分。以下是我现有的代码。

产品型号:

public function reviews(){
        return $this->belongsToMany(User::class,'reviews')->withPivot('comment','rating')->withTimestamps();
    }
public function getProductRatingAttribute(){
        return $this->reviews()->average('rating');
    }

用户模型:

public function reviews(){
        return $this->belongsToMany(Product::class,'reviews')->withPivot('comment','rating')->withTimestamps();
    }

为评论迁移

Schema::create('reviews', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
            $table->unsignedBigInteger('user_id');
            $table->unsignedBigInteger('product_id');
            $table->string('comment')->nullable();
            $table->integer('rating');
            $table->foreign('user_id')->references('id')->on('users');
            $table->foreign('product_id')->references('id')->on('products');
        });

我尝试使用以下代码构建预期的输出,但它导致 N+1 问题,因为它没有利用 Laravel Eloquent 的急切加载。

$s = Product::with('reviews')->append('product_rating');

当我检查望远镜时,它会产生 6 个查询,当数据很大时会导致性能问题。

预期输出:

{
  "msg": [
    {
      "id": 4,
      "created_at": "2021-04-09T07:32:35.000000Z",
      "updated_at": "2021-04-09T07:32:35.000000Z",
      "name": "MacDonald",
      "nickname": "MCD",
      "users_id": 1,
      "price": "0.00",
      "product_rating": "3.3333",
      "reviews": [
        {
          "id": 1,
          "name": "John Smith",
          "email": "john.smith@hotmail.com",
          "email_verified_at": null,
          "created_at": "2021-04-08T13:29:13.000000Z",
          "updated_at": "2021-04-08T13:29:13.000000Z",
          "role": 0,
          "pivot": {
            "product_id": 4,
            "user_id": 1,
            "comment": "Ouch",
            "rating": 3,
            "created_at": "2021-05-01T11:51:26.000000Z",
            "updated_at": "2021-05-01T11:52:07.000000Z"
          }
        },
        {
          "id": 2,
          "name": "Kelvin Ooi",
          "email": "kelvin.ooi@hotmail.com",
          "email_verified_at": null,
          "created_at": "2021-04-08T13:29:13.000000Z",
          "updated_at": "2021-04-13T12:07:11.000000Z",
          "role": 1,
          "pivot": {
            "product_id": 4,
            "user_id": 2,
            "comment": "Ouch",
            "rating": 5,
            "created_at": "2021-05-01T11:51:26.000000Z",
            "updated_at": "2021-05-01T11:52:07.000000Z"
          }
        },
        {
          "id": 1,
          "name": "John Smith",
          "email": "john.smith@hotmail.com",
          "email_verified_at": null,
          "created_at": "2021-04-08T13:29:13.000000Z",
          "updated_at": "2021-04-08T13:29:13.000000Z",
          "role": 0,
          "pivot": {
            "product_id": 4,
            "user_id": 1,
            "comment": "Ouch",
            "rating": 2,
            "created_at": "2021-05-01T11:51:26.000000Z",
            "updated_at": "2021-05-01T11:52:07.000000Z"
          }
        }
      ]
    },
    {
      "id": 10,
      "created_at": null,
      "updated_at": null,
      "name": "Mary Bown",
      "nickname": "MB",
      "users_id": 1,
      "price": "2.88",
      "product_rating": "2.0000",
      "reviews": [
        {
          "id": 1,
          "name": "John Smith",
          "email": "john.smith@hotmail.com",
          "email_verified_at": null,
          "created_at": "2021-04-08T13:29:13.000000Z",
          "updated_at": "2021-04-08T13:29:13.000000Z",
          "role": 0,
          "pivot": {
            "product_id": 10,
            "user_id": 1,
            "comment": "Ouch",
            "rating": 2,
            "created_at": "2021-05-01T11:51:26.000000Z",
            "updated_at": "2021-05-01T11:52:07.000000Z"
          }
        }
      ]
    },
    {
      "id": 11,
      "created_at": null,
      "updated_at": null,
      "name": "Pizza Hut",
      "nickname": "pizzahut",
      "users_id": 1,
      "price": "4.10",
      "product_rating": null,
      "reviews": [
        
      ]
    },
    {
      "id": 12,
      "created_at": "2021-04-09T08:00:42.000000Z",
      "updated_at": "2021-04-09T08:00:42.000000Z",
      "name": "Domino Pizza",
      "nickname": "domino",
      "users_id": 3,
      "price": "0.00",
      "product_rating": null,
      "reviews": [
        
      ]
    },
    {
      "id": 13,
      "created_at": "2021-04-26T16:12:53.000000Z",
      "updated_at": "2021-04-26T16:12:53.000000Z",
      "name": "Chicken Chop",
      "nickname": "chickchop",
      "users_id": 3,
      "price": "0.00",
      "product_rating": null,
      "reviews": [
        
      ]
    }
  ]
}

【问题讨论】:

    标签: php laravel laravel-5 eloquent eloquent-relationship


    【解决方案1】:

    追加是对每条记录执行查询。

    为什么不对集合本身执行平均?

    $s = Product::with('reviews')->get();
    $avg = $s->avg('pivot.rating');
    

    或者,您可以修改关系方法以包含平均评分的原始选择。

    【讨论】:

    • 嗨,请重新检查我的主线程,我已经更新了预期的输出。我很早就尝试过您的解决方案,但它不允许我直接导入相应产品的平均评分。
    猜你喜欢
    • 2019-07-27
    • 2022-01-09
    • 2021-03-06
    • 2014-10-23
    • 2019-07-05
    • 2018-05-16
    • 1970-01-01
    • 2020-05-06
    相关资源
    最近更新 更多