How to merge child key pairs to parents in Laravel models - laravel

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!

You can use the flatten method.
$data = MyData::with('new_data')->first()->flatten();
flatten docu

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

Related

How to add object to existing Laravel Query?

What I want to do is add an object to the existing query.
This is my work in progress right now:
$users = ModelUser::where('date_created', $date)->get();
foreach($users as $user){
$obj = ['test1'=> 'val1','test2' => 'val2','test3'=> 'val3',];
$users['items'] = $obj;
}
return $users;
what I'm hoping is a result is like this.
{"username":'Username1', "Fname":'fname1', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
"username":'Username2', "Fname":'fname2', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
"username":'Username3', "Fname":'fname3', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
"username":'Username4', "Fname":'fname4', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
}
Where the items are like in a sub object.
Convert it into a collection and push into it
https://laravel.com/docs/9.x/collections#method-push
Just to understand a bit more, does the "items" element you want to add to the user object have any relationship at the database level?
If so, it would be better to define a relationship within the ModelUser https://laravel.com/docs/9.x/eloquent-relationships#defining-relationships
In case not, I see you're using a $user as an array, but actually $user is a ModelUser element.
So a trick, definitely not recommended, would be:
$user->items = $obj;
You can use laravel map as
$users = ModelUser::where('date_created', $date)->get();
will return a collection. So your expected code will be something like the following
$users = $users
->map(function ($user) use ($obj) {
return $user->items = $obj;
})
);

GroupBy from relations using laravel eloquent

I have TypeOfVehicle model that has many Vehicle.
How can I group all vehicles by type of vehicle name with counts to get something like this
[
'Sedan' => 10,
'SUV' => 25,
'Crossover' => 5
]
I assume you have eloquent relation type in Vehicle model, e.g.:
public function type()
{
return $this->belongsTo('\App\TypeOfVehicle');
}
So, you can get you data this way:
$result = Vehicle::select('vehicle_type_id', DB::raw('count(vehicle_type_id) as cnt'))
->with('type') // with your type relation
->groupBy('vehicle_type_id') // group by type of vehicle
->get() // get collection from database
->pluck('cnt', 'type.name') // get only needful data
->toArray(); // cast to array if necessary
You can use
$counts = DB::table('tablename')
->select('TypeOfVehicle', DB::raw('count(*) as total'))
->groupBy('TypeOfVehicle')
->get();
Counting Related Models
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
$typeOfVehicles = App\TypeOfVehicle::withCount('vehicles')->get();
foreach ($typeOfVehicles as $typeOfVehicle) {
echo $typeOfVehicle->vehicles_count;
}
Try this it gives you your solution
$vehicle=Vehicle::all();
$grouped = $vehicle->groupBy(function ($item, $key) {
return substr($item['that_coloumn_name_like_type'], 0);
});
$groupCount = $grouped->map(function ($item, $key) {
return collect($item)->count();
});
//dd($groupCount); to check it work correctly

How to remove duplicate value between 2 array, Laravel?

I want to remove duplicated value between 2 arrays. How can I do?
1, 3, 4, 6 are duplicated in a both arrays, I want to unique values.
I using map() to show arrays of item_id contains of quantity but it's duplicate value, I don't want it.
$deliveries = $pickupsGroupByDepartment->first()->map(function ($q) {
return $q->deliveries->groupBy('delivery_date')->map(function($r) {
return $r->mapToGroups(function ($item) {
return [$item['item_id'] => $item['quantity']];
});
});
});
You can use array_unique function then combine it using array_merge function.
$array = array_unique (array_merge ($array1, $array2));
if your data is came from object in Laravel. you can use code below.
$result = $object1->merge($object2)->unique();
If the situation is dynamic data you can do this..
$results = [];
foreach($dynamicArray as $key => $array){
$results = array_unique (array_merge ($results, $array));
}
return $results;

Laravel eloquent whereIn with one query

In laravel, I can use many where rules as an array a run one query to the database using laravel eloquent where method to get needed result.
Code:
$where = [];
$where[] = ['user_id', '!=', null];
$where[] = ['updated_at', '>=', date('Y-m-d H:i:s')];
if($request->searchTerm) {
$where[] = ['title', 'like', '%' . $request->searchTerm . '%'];
}
Model::where($where)->get();
Question part:
Now I need to use Laravel Eloquent method whereIn with array params to get needed result with one query.
I tried by looping method but with many queries to the database.
Code:
$model = new Model;
$whereIn = [];
$whereIn[] = ['date', '>=', Carbon::now()->subDays(10)];
$whereIn[] = ['user_role', 'candidate'];
if (!empty($scope) && is_array($scope)) {
$whereIn[] = ['user_id', $scope];
}
if(is_array($employment) && !empty($employment)) {
$whereIn[] = ['employment', $employment];
}
if(is_array($experience) && !empty($experience)) {
$whereIn[] = ['experience', $experience];
}
foreach ($whereIn as $v) {
$model = $model->whereIn($v[0], $v[1]);
}
dump($model->get());
First I tired $model->whereIn($whereIn)->get() but it's return error. It's possible get results with one query using whereIn without looping?
Note: My $whereIn array will be dynamic array!
whereIn is a query builder function so you can't use it on the model directly. Instead you should create a query builder instance. I also suggest you use when instead of the if statements:
$models = Model::when(!empty($scope) && is_array($scope), function ($query) use ($scope) {
$query->whereIn('user_id', $scope);
})->when(!empty($employment) && is_array($employment), function ($query) use ($employment) {
$query->whereIn('employment', $employment);
})->when(!empty($experience) && is_array($experience), function ($query) use ($experience) {
$query->whereIn('experience', $experience);
})->get();
dump($models);
when essentially runs the function when the first parameter is true. There's more detail in the documentation under conditional clauses.
Since your $whereIn variable is an array of arrays it will work like :
$model->whereIn($whereIn[0][0], $whereIn[0][1])->get();
If it just a simple array then you can use :
$model->whereIn($whereIn[0], $whereIn[1])->get();
Do in Eloquent
$model = Model::whereIn('id', array(1, 2, 3))->get();
Or using Query builder then :
$model = DB::table('table')->whereIn('id', array(1, 2, 3))->get();

How to use sortBy after groupBy in collect in Laravel 5.3?

I need after get query from sql with Eloquent, create groupBy('date') and sortBy('price') with collect in Laravel 5.3.
In IndexController:
$flights = Flights::GetFlights($fromCity, $toCity, $fromDate);
$collection = collect($flights);
$sortFlight = $collection->groupBy('date')->sortBy('price');
In Model:
public function scopeGetFlights($query, $fromCity, $toCity, $fromDate)
{
// Between dates
$beforeDate = date('Y-m-d', strtotime($fromDate . '- 10 days'));
$afterDate = date('Y-m-d', strtotime($fromDate . '+ 10 days'));
$join = $query
-> join('airlines', 'airlines.pana', 'flights.airline')
-> where('flights.from_city', $fromCity)
-> where('flights.to_city', $toCity)
-> whereBetween('flights.date', [$beforeDate, $afterDate])
-> get([
'flights.*',
'airlines.pana as pana',
'airlines.name as airlineName'
]);
return $join;
}
Then Print_r($sortFlight), After print groupBy('date') is works
but sortBy('price') does not work!!!!
Where is my problem?
My solution for sorting values in a grouped collection in Laravel
$sponsors = Sponsor::with('sponsor_level')->whereStatus(1)->get();
// grouped by sponsor level name
$grouped = $sponsors->sortBy('sponsor_level.order')->groupBy(function($item, $key){
return $item->sponsor_level->name;
});
// finally sorted by sponsor name inside the group
return $grouped->map(function($item, $key){
return $item->sortBy('name');
});
You can chain these of course, I separated for better readability.
Try this single line
$sortFlight = $collection->groupBy('date')->sortBy('price')->values()->all();
From the doc
The sortBy method sorts the collection by the given key. The sorted collection keeps the original array keys, so in this example we'll use the values method to reset the keys to consecutively numbered indexes:
So after doing groupBy() do as follows.
$sorted = $collection->groupBy('date')->sortBy('price');
$sorted->values()->all();

Resources