关于产品数据要两次查询才能获取有没有可优化的空间?

问题咨询 · dosenje · 于 6年前 发布 · 2190 次阅读

关于产品数据要两次查询才能获取有没有可优化的空间?

/**
     * 初始化数据包括
     * 主键值:$this->_primaryVal
     * 当前产品对象:$this->_product
     * Meta keywords , Meta Description等信息的设置。
     * Title的设置。
     * 根据当前产品的attr_group(属性组信息)重新给Product Model增加相应的属性组信息
     * 然后,重新获取当前产品对象:$this->_product,此时加入了配置中属性组对应的属性。
     */
    protected function initProduct()
    {
        $primaryKey = Yii::$service->product->getPrimaryKey();
        $primaryVal = Yii::$app->request->get($primaryKey);
        $this->_primaryVal = $primaryVal;
        $product = Yii::$service->product->getByPrimaryKey($primaryVal);
        if ($product) {
            $enableStatus = Yii::$service->product->getEnableStatus();
            if ($product['status'] != $enableStatus){
                return false;
            }
        } else {
            return false;
        }
        $this->_product = $product;
        Yii::$app->view->registerMetaTag([
            'name' => 'keywords',
            'content' => Yii::$service->store->getStoreAttrVal($product['meta_keywords'], 'meta_keywords'),
        ]);
        Yii::$app->view->registerMetaTag([
            'name' => 'description',
            'content' => Yii::$service->store->getStoreAttrVal($product['meta_description'], 'meta_description'),
        ]);
        $this->_title = Yii::$service->store->getStoreAttrVal($product['meta_title'], 'meta_title');
        $name = Yii::$service->store->getStoreAttrVal($product['name'], 'name');
        //$this->breadcrumbs($name);
        $this->_title = $this->_title ? $this->_title : $name;
        Yii::$app->view->title = $this->_title;
        //$this->_where = $this->initWhere();

        // 通过上面查询的属性组,得到属性组对应的属性列表
        // 然后重新查询产品
        $attr_group = $this->_product['attr_group'];

        Yii::$service->product->addGroupAttrs($attr_group);

        // 重新查询产品信息。
        $product = Yii::$service->product->getByPrimaryKey($primaryVal);
        $this->_product = $product;
        return true;
    }
共收到 4 条回复 问题提问
Fecmall#16年前 1 个赞

1.如果使用active recode 的方式,我没有找到可以一次查询的方式,原因如下:

1.1 AR方式,因为需要得到对象的各个attributes,对应到数据库表的各个字段,对于mysql的AR是先查询表结构,然后得到各个attributes,然后在进行下一步的查询,对于mongodb是没有表结构的,所以只能在AR里面通过方法定义,譬如: @fecshop/models/mongodb/Product.php方法中的 public function attributes()方法。

1.2 对于产品数据,引入了属性组的概念,不同的属性组对应的属性不同,因此,对于attributes()方法,是由两部分组成,默认定义的属性和动态引入的属性合并起来。也就是

Yii::$service->product->addGroupAttrs($attr_group);

执行后会设置$_customProductAttrs,进而将属性添加到AR中,代码如下:

/**
     * mongodb是没有表结构的,因此不能像mysql那样取出来表结构的字段作为model的属性
     * 因此,需要自己定义model的属性,下面的方法就是这个作用
     */
    public function attributes()
    {
        $origin = [
            '_id',
            'name',
            'spu',
            'sku',
            'weight',
            'score',
            'status',
            'qty',
            'min_sales_qty',
            'is_in_stock',
            'visibility',
            'url_key',
            //'url_path',
            'category',
            'price',
            'cost_price',
            'special_price',
            'special_from',
            'special_to',
            'tier_price',
            'final_price',   // 算出来的最终价格。这个通过脚本赋值。
            'new_product_from',
            'new_product_to',
            'freeshipping',
            'featured',
            'upc',
            'meta_title',
            'meta_keywords',
            'meta_description',
            'image',
            'sell_7_count',
            'sell_30_count',
            'sell_90_count',
            'description',
            'short_description',
            'custom_option',
            'remark',
            'created_at',
            'updated_at',
            'created_user_id',
            'attr_group',
            'reviw_rate_star_average',    //评论平均评分
            'review_count',                    //评论总数
            'reviw_rate_star_average_lang', //(语言)评论平均评分
            'review_count_lang',            //(语言)评论总数
            'favorite_count',                // 产品被收藏的次数。
            'relation_sku',            // 相关产品
            'buy_also_buy_sku',        // 买了的还买了什么
            'see_also_see_sku',        // 看了的还看了什么

        ];
        if (is_array(self::$_customProductAttrs) && !empty(self::$_customProductAttrs)) {
            $origin = array_merge($origin, self::$_customProductAttrs);
        }

        return $origin;
    }

因此对于使用AR的方式,我没有找到省略一次查询的方法,因为必须先经过第一次查询得到属性组,

2.如果不使用AR,是可以的,直接查出来就行,但是AR的很多便利性就不能用了。

3.mongodb的并发查询非常优秀,按照主键查2次并不会带来太大的问题,最后折中的方案,就是您上面贴的代码,消耗一次查询带来开发的遍历性

4.产品页面,分类页面,一般要做整页缓存,动态数据用ajax加载,因此产品页面的两次查询的次数又被削弱

最后,如果您找到好的方式,就贴一下代码,一起学习

dosenje#26年前 0 个赞

@Terry #1楼 我也是想了没有想到好的方法,谢谢解惑。

Fecmall#36年前 1 个赞

如果想一次查询是可以的,

@fecshop/services/product/ProductMongodb.php 里面有一个方法, 直接查询出来产品数据,不是AR的方式。

/**
     * @property $primaryKey | String 主键
     * @return  array ,和getByPrimaryKey()的不同在于,该方式不走active record,因此可以获取产品的所有数据的。
     */
    public function apiGetByPrimaryKey($primaryKey)
    {
        $collection = $this->_productModel->find()->getCollection();
        $cursor = $collection->findOne(['_id' => $primaryKey]);
        $arr = [];
        foreach ($cursor as $k => $v) {
            $arr[$k] = $v;
        }

        return $arr;
    }

这种方式失去了AR的开发便利性。

dosenje#46年前 1 个赞

@Terry #3楼 打脸:smile:,我找的还是不详细。

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册
Your Site Analytics