4

Old PHP user here but new to Laravel, I need help(answers or link to related solution)...

If I have a relation model(or collection, I get confused here)...

$data = MyData::with('new_data')->first();

resulting with...

data = {
   a: 1,
   b: 2,
   new_data: {
     c: 3
   } 
}

Is there an easy eloquent or collection function to merge new_data key pairs to the parent data? such that will result to this...

data = {
   a: 1,
   b: 2,
   c: 3
}

I've tried flatten, flatMap, mapWithKeys, and other examples but failed to get the results I wanted. If there's no easy solution to this, this would be my long approach...

$raw_data = MyData::with('new_data')->first();
$data = collect($raw_data)->put('c', $raw_data->new_data->c);

thanks!

Jacobski
  • 741
  • 6
  • 10
  • Use a `join` in eloquent query to perform this. Is there any relation between these two tables? – Shahrukh May 20 '21 at 14:11
  • yes there is. The data''s table have a new_data_id that points to NewData's ID. public function new_data() { return $this->belongsTo(NewData::class); } I was using join before but I've read somewhere that "eager loading" is much faster – Jacobski May 20 '21 at 14:18
  • Query Builders are pretty fast compared to eloquent if we are talking about multiple joins. You can test the performance like https://www.youtube.com/watch?v=3TJfR1Ta4GU&t=138s . – Sandeep Dhakal May 20 '21 at 16:23

2 Answers2

2

You can use the flatten method.

$data = MyData::with('new_data')->first()->flatten();

flatten docu

  • I don't think flatten works directly with eloquent models but trying collect($data)->flatten(); gives me an array of values without keys. data = [1,2,3] – Jacobski May 20 '21 at 14:46
1

You can use power of array_walk_recursive to get that result. Lets build our custom function to flatten such models. Try this solution

$myData = MyData::with('new_data')->first();

function flattenMyModel($model) {
   $modelArr = $model->toArray();
   $data = [];
   array_walk_recursive($modelArr, function ($item, $key) use(&$data) {
       $data[$key] = $item;
   });
   return $data;
}

$myDataArr = flattenMyModel($myData);

dd($myDataArr);

You can easily do it using a query builder or using Model::join(); Here's how I would have done it.

$datas = DB::table('my_data as md')
             ->join('new_data as nd','md.id','nd.my_data_id')
             ->selectRaw('md.a,md.b,nd.c')
             ->first(); 

You can see more about eager loading and join here laravel-eager-loading-vs-explicit-join

Sandeep Dhakal
  • 299
  • 2
  • 11