You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeIgniter ORM嵌套关联查询功能等效实现求助

How to Get Nested Relational Results in CodeIgniter (Like Sequelize's include)

Hey there, I totally get the frustration—CodeIgniter’s query builder doesn’t have that built-in nested relational result feature like Sequelize’s include out of the box. But don’t worry, we can easily replicate that behavior with a bit of PHP post-processing or a structured query approach. Let me walk you through a couple of solid solutions:

Option 1: Manual N+1 Query (Simple, for Small Datasets)

This approach is straightforward and easy to read, though it runs one initial query for users plus one query per user for payments (so "N+1" queries total). Great for small datasets where performance isn’t critical:

// First, fetch all users from the database
$users = $this->db->get('users')->result_array();

// Loop through each user to attach their payments
foreach ($users as &$user) {
    $user['payments'] = $this->db
        ->where('user_id', $user['user_id'])
        ->get('payments')
        ->result_array();
}

// Now $users contains your nested structure!
// Example output:
// [
//   ["user_id" => 1, "payments" => [["payment_id" => 1], ["payment_id" => 2]]],
//   ["user_id" => 2, "payments" => [["payment_id" => 3], ["payment_id" => 4]]]
// ]

Option 2: Single Query + PHP Reorganization (Better for Large Datasets)

For larger datasets, a single JOIN query followed by PHP restructuring is more efficient (only one round trip to the database). Here’s how to do it:

// Run a JOIN query to get flat, combined results
$flat_results = $this->db
    ->select('u.user_id, p.payment_id')
    ->from('users u')
    ->join('payments p', 'u.user_id = p.user_id', 'left') // Use left join to include users with no payments
    ->get()
    ->result_array();

// Restructure the flat results into nested arrays
$nested_users = [];
foreach ($flat_results as $row) {
    $user_id = $row['user_id'];
    
    // Initialize the user entry if it doesn't exist yet
    if (!isset($nested_users[$user_id])) {
        $nested_users[$user_id] = [
            'user_id' => $user_id,
            'payments' => []
        ];
    }
    
    // Add the payment only if it exists (avoids empty entries from left joins)
    if (!empty($row['payment_id'])) {
        $nested_users[$user_id]['payments'][] = [
            'payment_id' => $row['payment_id']
        ];
    }
}

// Convert the associative array to an indexed array if needed
$nested_users = array_values($nested_users);

Bonus: Reusable Model Method

If you need this functionality often, wrap it in a custom model method to keep your code clean (just like Sequelize’s model methods):

class UserModel extends CI_Model {
    public function findAllWithPayments() {
        $flat_results = $this->db
            ->select('u.user_id, p.payment_id')
            ->from('users u')
            ->join('payments p', 'u.user_id = p.user_id', 'left')
            ->get()
            ->result_array();

        $nested_users = [];
        foreach ($flat_results as $row) {
            $user_id = $row['user_id'];
            if (!isset($nested_users[$user_id])) {
                $nested_users[$user_id] = [
                    'user_id' => $user_id,
                    'payments' => []
                ];
            }
            if (!empty($row['payment_id'])) {
                $nested_users[$user_id]['payments'][] = ['payment_id' => $row['payment_id']];
            }
        }

        return array_values($nested_users);
    }
}

Then use it like this:

$this->load->model('UserModel');
$users_with_payments = $this->UserModel->findAllWithPayments();

内容的提问来源于stack exchange,提问作者Vahid Najafi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 18:57:37