7

NOTE Please do not suggest using Eloquent, this is specifically for the Laravel query builder.

For performance reasons we are using Query Builder to retrieve results from a table:

DB::table('posts')->get();

If we then want to join a relation onto that query:

DB:table('posts')
    ->leftJoin('comments', 'posts.id', '=', 'comments.post_id')
    ->get();

The results are merged into the array of each post:

[
    'id'                => 1,
    'title'             => 'My Blog Post',
    'content'           => '<h1>This is a post</h1><p>hello world</p>',
    'post_author'       => 'Billy',
    'comment'           => 'This is a comment',
    'comment_author'    => 'Andrew',
]

How can we have the joined results placed into a nested array? Such as:

[
    'id'                => 1,
    'title'             => 'My Blog Post',
    'content'           => '<h1>This is a post</h1><p>hello world</p>',
    'post_author'       => 'Billy',
    'comment'           => [
        'id'                => 22,
        'comment'           => 'This is a comment',
        'comment_author'    => 'Andrew',            
    ],
]
5
  • Relations are only used in case of Eloquent. Laravel Query Builder does not handle relations. @SougataBose Commented Jan 16, 2017 at 9:56
  • What is the issue with the format return by query? Commented Jan 16, 2017 at 9:58
  • Are looking for some thing like GROUP BY in MySQL for grouping all the comments for each post ? Commented Jan 16, 2017 at 10:04
  • 2
    @SougataBose The question clearly states not to use Eloquent......... Commented Jan 16, 2017 at 10:10
  • In laravel you can't get above output using query builder. For this either you will need to write your own classes and functions which can then return your desired format of output. Commented Jan 16, 2017 at 10:12

5 Answers 5

3

Dont think its doable out of the box without Eloquent.

You can go the primitive route:

$results = DB:table('posts')
    ->leftJoin('comments', 'posts.id', '=', 'comments.post_id')
    ->select('posts.*', 'comments.*', 'comments.id as comments_id')
    ->get(); 

foreach($results as &$result) 
{ 
    $result['comment'] = [
        'id' => $result['comment_id'], 
        'comment' => $result['comment'], 
        'comment_author' => $result['comment_author']
    ]; 
    unset($result['comment_author'], $result['comment_id']);
}
Sign up to request clarification or add additional context in comments.

5 Comments

I wish eloquent had a more subtle way of handling results, at least as an option.
Your solution does not group all comments of each post as a nested-array, actually each post will appear N times, when N is its comments number.
This will make the query very slower, as if there are more than 10000+ post, then query itself will take some seconds to executes
@JagadishMeghval the question was how to get join results in a nested manner. It has nothing to do with performance.
Does eloquent the same as on this answer?
1

Since you work with DB facade and not Eloquent, and cannot use built-in with() method, you have to implement it yourself:

$posts = DB::table('posts')->get()->toArray();
$comments = DB::table('comments')->get()->toArray();

foreach($posts as &$post)
{
    $post->comments = array_filter($comments, function($comment) use ($post) {
        return $comment->post_id === $post->id;
    });
}

return $posts;

If you want to get rid of post_id for comments entries, you can do:

$posts = DB::table('posts')->get()->toArray();
$comments = DB::table('comments')->get()->toArray();

foreach($posts as &$post)
{
    $comments = array_filter($comments, function($comment) use ($post) {
        return $comment->post_id === $post->id;
    });

    $post->comments = array_map(function ($comment) {
        unset($comment->id);
        return $comment;
    }, $comments);
}

return $posts;

(I guess the runtime would be similar to with(), since after-all MySql does not provide this functionality out-of-the-box).

Comments

0

Here some new information:

$data= $DB->select("select posts.*,comments from posts left join comments on posts.id = comments.post_id");

I am not sure it is work or not but you can try

1 Comment

This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
0

You can try with this

$data= $DB->select("select *,(select json_agg(datas) from (select * from comments where posts.id=comments.post_id) as datas) as comments from posts;");

But you may need to decode at comments as well

Comments

0
$products = Category::with('product')->get(array('category.qty','category.product_id','category.net_unit_price as price'));

    foreach ($products as $p){
        $pl['name'] = $p->product->name;
        $pl['image'] = $p->product->image;
        unset($pl->product);
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.