Yii2中使用leftJoin能否将关联表结果存入子数组?
问题场景与疑问
假设数据库中Product表与Account表存在关联,使用joinWith()查询时:
$products = Product::find()->joinWith('account')->asArray()->all();
返回结果会将Account数据存入子数组:
[ 'title' => 'Product title', 'price' => 'Product price', 'accountId' => 1, 'account' => [ 'id' => 1, 'name' => 'Account name', 'location' => 'Account location' ] ]
而使用leftJoin()查询时:
$products = Product::find() ->select('Product.*') ->leftJoin('Account', 'Account.id = Product.accountId') ->addSelect([ 'Account.name as accountName', 'Account.location as accountLocation', ]) ->all();
返回的Account字段是和Product字段平级的:
[ 'title' => 'Product title', 'price' => 'Product price', 'accountId' => 1, 'accountName' => 'Account name', 'accountLocation' => 'Account location' ]
疑问:能否通过leftJoin()实现将关联表结果存入子数组的效果?
实现方法
当然可以,leftJoin()本身仅返回扁平字段结构,需要通过额外处理来组装子数组,以下是几种实用方案:
方案1:手动遍历重组数组
执行leftJoin查询后,遍历结果集,将指定字段提取为子数组:
// 执行leftJoin查询,获取包含Account字段的扁平结果 $products = Product::find() ->select('Product.*, Account.name, Account.location') ->leftJoin('Account', 'Account.id = Product.accountId') ->asArray() ->all(); // 遍历重组account子数组 foreach ($products as &$product) { // 组装account子数组 $product['account'] = [ 'name' => $product['name'], 'location' => $product['location'] ]; // 移除平级的冗余字段 unset($product['name'], $product['location']); } unset($product); // 释放引用变量
方案2:在模型中通过afterFind自动处理
如果使用ActiveRecord对象而非数组结果,可以在Product模型中重写afterFind方法,自动将平级的Account字段封装为子数组:
class Product extends ActiveRecord { // 定义用于存储Account数据的属性 public $account; public function afterFind() { parent::afterFind(); // 检查是否存在Account相关字段,存在则组装子数组 if (isset($this->name, $this->location)) { $this->account = [ 'name' => $this->name, 'location' => $this->location ]; // 移除平级字段 unset($this->name, $this->location); } } // 其他模型逻辑代码... }
之后执行leftJoin查询时,返回的Product对象会自动包含account子数组。
方案3:利用数据库JSON函数构造子数组(数据库依赖)
部分数据库(如PostgreSQL、MySQL 8.0+)支持JSON构造函数,可以在select语句中直接生成JSON格式的子数组:
// MySQL 8.0+ 用法 $products = Product::find() ->select([ 'Product.*', "JSON_OBJECT('name', Account.name, 'location', Account.location) as account" ]) ->leftJoin('Account', 'Account.id = Product.accountId') ->asArray() ->all(); // 需要将JSON字符串转为数组的话,可添加处理 foreach ($products as &$product) { $product['account'] = json_decode($product['account'], true); }
注意这种方式依赖特定数据库的功能,跨数据库移植性较差。
内容的提问来源于stack exchange,提问作者daniil sidorov
相关产品推荐
相关产品推荐

