Process Collection through Map function - laravel

I get a Collection from a Query in Laravel.
Actually, I'm processing collection like that:
foreach ($cts as $ct) {
$array[$ct->id] = $ct->category->name;
}
It outputs this:
array:2 [▼
1158 => "Junior por Equipo"
1160 => "Varonil por Equipo"
]
Now, I would like to user map() function over muy collection as I like it better:
MyModel::get()
->get()
->map(function ($item, $value){
return [ $item->id => $item->category->name ];
})->toArray();
But now, I get :
array:2 [▼
0 => array:1 [▼
1158 => "Junior por Equipo"
]
1 => array:1 [▼
1160 => "Varonil por Equipo"
]
]
How should I do to output it like the first case?

You don't have to map the collection, just use MyModel::lists('name', 'id' ) ;

There is a collection method for that. pluck() and eloquent lists()
no its preferred to use pluck for getting some columns only. previously lists() was used.
see https://laravel.com/docs/5.3/collections#method-pluck
as the document says
The pluck method retrieves all of the values for a given key/keys only
so it would be something like this.
Model::get()->pluck('name','id);
Than you can do toArray() on the result if you want to get an array instead of a collection.

Related

Retrieving data from a countries API

I'm using an API to get a list of countries in Laravel. I have been able to isolate the countries list only but the countries now have an inner array with details of the country. I only need the name. I've tried using foreach but it didn't work.
This below is the result from the api
#items: array:2 [▼
"countries" => array:198 [▼
0 => array:4 [▼
"code" => "BT"
"name" => "Bhutan"
"geonameid" => 1252634
"depends_on" => null
]
1 => array:4 [▶]
This below is the code fetching it
$response = Http::withHeaders([
'x-rapidapi-host' => 'world-geo-data.p.rapidapi.com',
'x-rapidapi-key' => '1fa601995fmshcc1d2fcc97ee24cp1ac29djsn9b9b11cc10ec',
//'x-rapidapi-key' => config('app.rapid_api_key'),
])->get('https://world-geo-data.p.rapidapi.com/countries');
//dd($response->collect());
return $response->collect()->pluck('name')
->all();
I'm trying to get only the name value. the return is returning null
I think this is what you want:
return collect($response->collect()["countries"])->pluck('name');
The result will be like:

merging collections grouped multiple times

I have a collection grouped (multiple times) like this:
Illuminate\Support\Collection {#1883 ▼
#items: array:1 [▼
57082 => Illuminate\Support\Collection {#1885 ▼
#items: array:1 [▼
"07-2021" => Illuminate\Database\Eloquent\Collection {#1863 ▼
#items: array:1 [▼
343 => Illuminate\Database\Eloquent\Collection {#1864 ▼
#items: array:1 [▶]
}
]
}
]
}
]
}
I have another collection that could have same values or not, and I need to merge these 2 collections with merged elements.
I tried with this, without success (I lose first "group"):
$fstCollection = $fstCollection->mapWithKeys(function ($items, $key) use ($sndCollection) {
return $sndCollection->get($key) ? $items->merge($sndCollection->get($key)) : $items;
});
I'm expecting your are loosing the key, by using mapWithKeys() wrong, in general that method is used, by returning an associative array, representing the key to map to and the value.
So changing the closure logic to the following, will keep the first group.
$collection = $sndCollection->get($key) ? $items->merge($sndCollection->get($key)) : $items;
return [$key => $collection];
Alternatively, just using map() will solve your problem, map() preserves the keys.
$fstCollection = $fstCollection->map(function ($items, $key) use ($sndCollection) {
return $sndCollection->get($key) ? $items->merge($sndCollection->get($key)) : $items;
});

Laravel reducing relationship queries

I have two models. Expense and Method. I want to grab the sum of all expenses for each method type. I have four types:
- bank
- credit-card
- wallet
- savings
Each Expense belongsTo a Method and each Method hasMany Expenses. So it's a One-to-Many relation. So a method_id is stored for each Expense.
The following query works to get the sum of all expenses that have a method with the type bank for example:
$type = 'bank';
$expenses = auth()->user()->expenses()->with('method')->whereHas('method', function ($query) use ($type) {
$query->where('type', $type);
})->sum('amount');
But the thing is, if I want to get the total amount of all expenses for each method type, I will have to run too many queries. I would prefer just grabbing all Expenses, and then filtering through them to get the sum of all expenses for each method type.
The following for example doesn't work:
$expenses = auth()->user()->expenses()->with('method')->get();
$bank_balance = $expenses->filter(function ($expense)
{
$expense->whereHas('method', function ($query) {
$query->where('type', 'bank');
})->get(); // with or without ->get()
});
Any ideas how to get what I want by not using too many queries?
Edit:
I've unaccepted the chosen answer because it didn't give me what I needed in the end. I need to be able to do something like this in my view:
{{ $bank_balance }}
Which means, with xyz's answer, I wouldn't be able to do that, since I cannot distinguish between them. I only get results based on method_id's, but I need to be able to distinguish them by the method name.
DigitalDrifter's answer is the one that almost does the trick, but it gives me this:
Collection {#800 ▼
#items: array:3 [▼
"bank" => Collection {#797 ▼
#items: array:30 [▼
0 => array:2 [▼
"type" => "bank"
"amount" => 1536
]
1 => array:2 [▶]
2 => array:2 [▶]
3 => array:2 [▶]
4 => array:2 [▶]
5 => array:2 [▶]
]
}
"credit-card" => Collection {#798 ▶}
"wallet" => Collection {#799 ▶}
]
}
And I basically need something simple like this:
"bank" => "total sum here for all expenses that have a method of 'bank'"
"credit-card" => "total sum here for all expenses that have a method of 'credit-card'"
And so on..
I think this bit ->groupBy('type')->each->sum('amount') does the trick, but not completely. It does group by type but it does not give a sum for each type, as you can see in the collection example above.
You can group by the method id and then sum the result in a select statement.
The following is untested.
$expenses = auth()->user()
->expenses()
->select(DB::raw('SUM(amount) as total'), 'other_select_fields', ...)
->with('method')
->groupBy('method_id')
->get();
You could do this using the available collection methods:
$expenses = auth()->user()->expenses()->with('method')->get();
$groupedSums = $expenses->map(function ($expense) {
return [
'type' => $expense['method']['type'],
'amount' => $expense['method']['amount']
];
})->groupBy('type')->each->sum('amount');

Convert an array of array onto Collection Laravel

I have an array of array which results from several sql requests.
First I make a sql request in a foreach in order to have all the datas i need
foreach ($users as $user) {
// Two different Eloquent requests
$todo = User::select().....where('users.id' = $id);
$done = User::select().....where('users.id' = $id);
// I have operation on Collection that work fine ...
$totalTimes = $todo->toBase()->sum('dureeformation') ;
$spendTimes = $done->toBase()->sum('dureeformation') ;
$remainingTimes = $totalTimes - $spendTimes;
$all[] = ['user_id' => $id, 'totalTime' => $totalTimes, 'spendTime' => $spendTimes,'remainingTime' => $remainingTimes ];
}
My issue is the following... Outside the foreach i display the values and i have this array of array ...
array:16 [▼
0 => array:4 [▼
"user_id" => 1
"totalTime" => 465
"spendTime" => 0
"remainingTime" => 465
]
1 => array:4 [▼
"user_id" => 3
"totalTime" => 375
"spendTime" => 0
"remainingTime" => 375
]
I would need to have a Collection instead ... I tried to make $all = Collect(....) but i doesn't give me the expected result.
I need a collection because i have to create a Collection with this created collection and another one from another request.
Concerning this part i already had this case and i can solve it.
Thanks for your help
try this helper function :
$collection = collect($all);
This function will convert your array to collection.

Get relation of relation

I'm trying to get the comments of the links with laravel relationship, the comments of links return normally, but I don't know how to get it in view or dd(), how can I do it?
Controller:
$page = Page::where('friendly_url', $id)
->select('id', 'photo', 'friendly_url', 'name', 'description', 'followers', 'links', 'tag_id', 'links_clicks')
->with('ptag', 'links', 'links.comments', 'links.tag')
->with(['links.comments.user' => function($query) {
$query->select('id', 'name', 'lastname');
}])->with(['links.comments.userProfile' => function($query) {
$query->select('id', 'photo');
}])->first();
dd($page->getRelation('links')
Collection {#301 ▼
#items: array:2 [▼
0 => Link {#307 ▼
#relations: array:2 [▼
"comments" => Collection {#316 ▼
#items: array:1 [▶]
"tag" => Tag {#322 ▶}
]
dd($page->getRelation('links')->getRelation('comments'))
BadMethodCallException
Method getRelation does not exist.
dd($page->getRelation('links')->comments)
Exception
Property [comments] does not exist on this collection instance.
EDIT:
I want to show the attributes of comment and comment.user, how I can do it?
foreach($page->getRelation('links')->pluck('comments') as $comment) {
dd($comment);
}
Collection {#327 ▼
#items: array:1 [▼
0 => Comment {#325 ▼
#attributes: array:5 [▼
"id" => 3
"content" => "teste"
"link_id" => 1
"user_id" => 1
"created_at" => "2018-01-11 00:47:32"
]
#relations: array:2 [▼
"user" => User {#330 ▼
#attributes: array:3 [▼
"id" => 1
"name" => "Halysson"
"lastname" => "Teves dos Santos"
]
}
"userProfile" => UserProfile {#326 ▶}
]
Try this-
foreach($page->links as $link){
$comments = $link->comments;
}
You should define relations first on relevent models and then using 'with' function can load models with relations OR a relation can be called directly by single model see documentation for further details
eg: you have defined a relation for user to phone, as user has a phone, one to one relation. in user model define a relation like
public function phone()
{
return $this->hasOne('App\Phone');
}
now to call this relation on user model instance.
$user = User::find(1);
dd($user->phone);
Because you're using the select() method, you also need to include all the foreign keys in it to allow Eloquent to be able to load these relationships.
But since you just start using Laravel, I'd recommend you to just remove select() method from this complex query.
If you want the links of a page :
$page->links
if you want all the comments of a page :
$page->links->pluck('comments')
that's it :)

Resources