du9843 2017-05-04 16:29
浏览 184
已采纳

聚合数据组为Yii2关系

In my Product model I have the following two methods; getOrderFeedback() is normal relation returning an ActiveQuery and getTotalAndAveFeedback() which returns an array of aggregate data for a given Product record.

/**
 * @return \yii\db\ActiveQuery
 */
public function getOrderFeedback()
{
    return $this->hasMany(OrderFeedback::className(), ['productID' => 'ID']);
}

/**
 * @return array
 */
public function getTotalAndAveFeedback()
{
    return $this->getOrderFeedback()
        ->select(['COUNT(*) AS num',
                  'AVG(rating) AS avg',
                  'FLOOR(AVG(rating)) AS full',
                  'MOD(AVG(rating), 1) AS decimal_portion',
                  '5 - FLOOR(AVG(rating)) - CEILING(MOD(AVG(rating),1)) AS empty'])->one();
}

When I have a group of Products and iterate over them to gather the totalAndAveFeedback for a single Product, the ActiveQuery is triggered causing a lazy style reading from the db. Something like the following

$my_products = Product::find()->with(['supplier', 'location'])
               ->where(['published' => 1])
               ->all();

# SELECT * FROM product WHERE published = 1; 
# Find all products
# SELECT * FROM supplier WHERE ID IN (s1, s2, s3);
# Eagerly load supplier
# SELECT * FROM location WHERE ID IN (l1, l2, l3, l4);
# Eagerly load location

foreach ($my_products as $product) {
   echo $product->supplier->supplier_name; 
   # supplier object available from eager loading
   echo $product->location->title;
   # location object available from eager loading
   echo $product->totalAndAveFeedback->decimal_portion; 
   # requires db access to 'lazy load' data for each product record
   # SELECT COUNT(*) AS num, AVG(rating) AS avg, FLOOR(AVG(rating)) AS full, MOD(AVG(rating), 1) AS decimal_portion, 5 - FLOOR(AVG(rating)) - CEILING(MOD(AVG(rating),1)) AS empty FROM `order_feedback` WHERE `productID`=pID
}

Is there a way to treat getTotalAndAveFeedback() as relation to allow a joinWith() / with() on a Product ActiveQuery so the data can be eagerly loaded for each Product and available in the same manner as the Supplier or Location relations?

I've tried removing the call to one() in getTotalAndAveFeedback() to allow the method to be treated as a relation, but the totalAndAveFeedback attribute of the Product records were all empty arrays where I'd expect an object with attributes such as decimal_portion as if I'd called a simple relation like Supplier.

Is this possible in Yii2?

  • 写回答

1条回答 默认 最新

  • duannao3402 2017-05-05 11:12
    关注
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTotalAndAveFeedback()
    {
        return $this->getOrderFeedback()
            ->select(['productID', 'COUNT(*) AS num',
                      'AVG(rating) AS avg',
                      'FLOOR(AVG(rating)) AS full',
                      'MOD(AVG(rating), 1) AS decimal_portion',
                      '5 - FLOOR(AVG(rating)) - CEILING(MOD(AVG(rating),1)) AS empty'])
            ->groupBy(['productID']);
    }
    

    As @Pa3Py6aka pointed out, the reason the array was empty when joining on the relation was without selecting the productID there was no link between the returned OrderFeedbacks and the Product.

    By adding the groupBy(['productID']) method call to the ActiveQuery each the OrderFeedbacks are eagerly loaded and accessible to the individualProduct objects.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog