Change Laravel belongsToMany() returned data format - php

I'm using belongsToMany() in my Laravel model and i need to change the function return format.
public function platform_information(): BelongsToMany
{
return $this->belongsToMany(
PlatformInformation::class,
'platform_information_artist',
'artist_id',
'platform_information_id')->withPivot([
'date', 'value'
]);
}
When I call the function
$artist->platform_information()
->orderBy('platform_information_id', 'asc')
->orderBy('date', 'asc')
->get()
Returns the following data:
[
{
"id": 1,
"platform": "spotify",
"information": "monthly_listeners",
"description": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"pivot": {
"artist_id": 1,
"platform_information_id": 1,
"date": "2022-11-09",
"value": 55400500
}
},
{
"id": 1,
"platform": "spotify",
"information": "monthly_listeners",
"description": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"pivot": {
"artist_id": 1,
"platform_information_id": 1,
"date": "2022-11-10",
"value": 55395190
}
},
{
"id": 2,
"platform": "spotify",
"information": "followers",
"description": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"pivot": {
"artist_id": 1,
"platform_information_id": 2,
"date": "2022-11-09",
"value": 25390584
}
},
{
"id": 2,
"platform": "spotify",
"information": "followers",
"description": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"pivot": {
"artist_id": 1,
"platform_information_id": 2,
"date": "2022-11-10",
"value": 25410584
}
}
]
The data obtained are correct, but not in the format in which I need them.
This is the format that i need:
[
{
"id": 1,
"platform": "spotify",
"information": "monthly_listeners",
"data" : [
{
"artist_id": 1,
"platform_information_id": 1,
"date": "2022-11-09",
"value": 55400500
},
{
"artist_id": 1,
"platform_information_id": 1,
"date": "2022-11-10",
"value": 55395190
}
]
},
{
"id": 2,
"platform": "spotify",
"information": "followers",
"data" : [
{
"artist_id": 1,
"platform_information_id": 2,
"date": "2022-11-09",
"value": 25390584
},
{
"artist_id": 1,
"platform_information_id": 2,
"date": "2022-11-10",
"value": 25410584
}
]
}
]
Is there any way to do this using the belongsToMany() function directly?
Or do I have to do it manually in the controller?

I had not tested it but what I have get from the question, it should work.
I am assuming that you have a model Artist in your Models directory.
$artist = \App\Models\Artist::with('platform_information')->get();
Then you can dd() to verify the format
dd($artist->toArray());

Related

Laravel Eloquent perform Aggregation function in the pivot relationship

I would like to perform the average rating of respective product which stored in the pivot table called "reviews".Below are my existing code.
Product Model:
public function reviews(){
return $this->belongsToMany(User::class,'reviews')->withPivot('comment','rating')->withTimestamps();
}
public function getProductRatingAttribute(){
return $this->reviews()->average('rating');
}
User Model:
public function reviews(){
return $this->belongsToMany(Product::class,'reviews')->withPivot('comment','rating')->withTimestamps();
}
Migration for the reviews
Schema::create('reviews', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('product_id');
$table->string('comment')->nullable();
$table->integer('rating');
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('product_id')->references('id')->on('products');
});
I have attempted to use the below to code construct the expected output but it leads N+1 issue because it does not take advantage of the eager loading of the Laravel Eloquent.
$s = Product::with('reviews')->append('product_rating');
As I check telescope, it produces 6 query which can lead performance issue when the data is large.
Expected output:
{
"msg": [
{
"id": 4,
"created_at": "2021-04-09T07:32:35.000000Z",
"updated_at": "2021-04-09T07:32:35.000000Z",
"name": "MacDonald",
"nickname": "MCD",
"users_id": 1,
"price": "0.00",
"product_rating": "3.3333",
"reviews": [
{
"id": 1,
"name": "John Smith",
"email": "john.smith#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-08T13:29:13.000000Z",
"role": 0,
"pivot": {
"product_id": 4,
"user_id": 1,
"comment": "Ouch",
"rating": 3,
"created_at": "2021-05-01T11:51:26.000000Z",
"updated_at": "2021-05-01T11:52:07.000000Z"
}
},
{
"id": 2,
"name": "Kelvin Ooi",
"email": "kelvin.ooi#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-13T12:07:11.000000Z",
"role": 1,
"pivot": {
"product_id": 4,
"user_id": 2,
"comment": "Ouch",
"rating": 5,
"created_at": "2021-05-01T11:51:26.000000Z",
"updated_at": "2021-05-01T11:52:07.000000Z"
}
},
{
"id": 1,
"name": "John Smith",
"email": "john.smith#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-08T13:29:13.000000Z",
"role": 0,
"pivot": {
"product_id": 4,
"user_id": 1,
"comment": "Ouch",
"rating": 2,
"created_at": "2021-05-01T11:51:26.000000Z",
"updated_at": "2021-05-01T11:52:07.000000Z"
}
}
]
},
{
"id": 10,
"created_at": null,
"updated_at": null,
"name": "Mary Bown",
"nickname": "MB",
"users_id": 1,
"price": "2.88",
"product_rating": "2.0000",
"reviews": [
{
"id": 1,
"name": "John Smith",
"email": "john.smith#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-08T13:29:13.000000Z",
"role": 0,
"pivot": {
"product_id": 10,
"user_id": 1,
"comment": "Ouch",
"rating": 2,
"created_at": "2021-05-01T11:51:26.000000Z",
"updated_at": "2021-05-01T11:52:07.000000Z"
}
}
]
},
{
"id": 11,
"created_at": null,
"updated_at": null,
"name": "Pizza Hut",
"nickname": "pizzahut",
"users_id": 1,
"price": "4.10",
"product_rating": null,
"reviews": [
]
},
{
"id": 12,
"created_at": "2021-04-09T08:00:42.000000Z",
"updated_at": "2021-04-09T08:00:42.000000Z",
"name": "Domino Pizza",
"nickname": "domino",
"users_id": 3,
"price": "0.00",
"product_rating": null,
"reviews": [
]
},
{
"id": 13,
"created_at": "2021-04-26T16:12:53.000000Z",
"updated_at": "2021-04-26T16:12:53.000000Z",
"name": "Chicken Chop",
"nickname": "chickchop",
"users_id": 3,
"price": "0.00",
"product_rating": null,
"reviews": [
]
}
]
}
Appending is performing the query on each record.
Why not perform average on the collection itself?
$s = Product::with('reviews')->get();
$avg = $s->avg('pivot.rating');
Alternatively you can modify the relationship method to include a raw select of the average rating.

Laravel I can't retrieve requester data using with

I am using this package
https://github.com/renoki-co/befriended
My issue is trying to get all my friends posts with my post including user's data, but the problem is the requester data is null.
$user = $request->user();
$followersPost = UserPost::with(['user' => function ($query) use ($user) {
$query->filterFollowingsOf($user);
}])->latest()->get();
return $followersPost;
Response
[
{
"id": 35,
"post_body": "The Requster Post",
"location_id": "4b0da1acf964a520b94c23e3",
"location_title": "Apple Infinite Loop",
"location_icon": "https://ss3.4sqi.net/img/categories_v2/shops/technology_bg_44.png",
"location_coordinate": "{"latitude":37.33167558501772,"longitude":-122.030189037323,"latitudeDelta":0.001,"longitudeDelta":0.001}",
"location_vicinity": "Cupertino - 1 Infinite Loop",
"user_id": 1,
"viewer_ids": null,
"created_at": "2020-12-06T18:08:58.000000Z",
"updated_at": "2020-12-06T18:08:58.000000Z",
"images": [
],
"musics": [
],
"movies": [
],
"emojs": [
],
"user": null
},
{
"id": 34,
"post_body": "Test Post",
"location_id": "4b0da1acf964a520b94c23e3",
"location_title": "Apple Infinite Loop",
"location_icon": "https://ss3.4sqi.net/img/categories_v2/shops/technology_bg_44.png",
"location_coordinate": "{"latitude":37.33167558501772,"longitude":-122.030189037323,"latitudeDelta":0.001,"longitudeDelta":0.001}",
"location_vicinity": "Cupertino - 1 Infinite Loop",
"user_id": 2,
"viewer_ids": null,
"created_at": "2020-12-06T18:08:14.000000Z",
"updated_at": "2020-12-06T18:08:14.000000Z",
"images": [
],
"musics": [
],
"movies": [
],
"emojs": [
],
"user": {
"id": 2,
"_id": "dfa19aa6-510b-4aaf-8475-4386da9de3d0",
"name": "Saleh",
"username": "saleh",
"email": "saleh#gmail.com",
"email_verified_at": null,
"avatar": "http://backend.mf.sa/storage/avatars/1607128041.jpg",
"location": null,
"gender": "male",
"bio": null,
"birthday": null,
"phone": null,
"created_at": "2020-12-05T00:27:02.000000Z",
"updated_at": "2020-12-05T00:27:21.000000Z"
}
},
{
"id": 24,
"post_body": null,
"location_id": null,
"location_title": null,
"location_icon": null,
"location_coordinate": null,
"location_vicinity": null,
"user_id": 3,
"viewer_ids": null,
"created_at": "2020-12-06T01:53:18.000000Z",
"updated_at": "2020-12-06T01:53:18.000000Z",
"images": [
],
"musics": [
{
"id": 4,
"post_id": 24,
"song_name": "Confetti",
"song_preview": "https://cdns-preview-6.dzcdn.net/stream/c-6eb643a05083c023f874f13739fc7c87-3.mp3",
"song_picture": "https://api.deezer.com/album/183603832/image",
"song_artist": "Little Mix",
"created_at": "2020-12-06T01:53:18.000000Z",
"updated_at": "2020-12-06T01:53:18.000000Z"
}
],
"movies": [
],
"emojs": [
{
"id": 16,
"post_id": 24,
"user_id": 3,
"emojy": "015-smile-1",
"created_at": "2020-12-06T01:59:15.000000Z",
"updated_at": "2020-12-06T01:59:15.000000Z",
"user": {
"id": 3,
"_id": "af65864b-f18a-4609-91db-336acbce1486",
"name": "Ali",
"username": "ali2323",
"email": "ali#gmail.com",
"email_verified_at": null,
"avatar": null,
"location": null,
"gender": "male",
"bio": null,
"birthday": null,
"phone": null,
"created_at": "2020-12-05T04:05:50.000000Z",
"updated_at": "2020-12-05T04:05:50.000000Z"
}
},
{
"id": 17,
"post_id": 24,
"user_id": 1,
"emojy": "089-broken-heart",
"created_at": "2020-12-06T16:58:07.000000Z",
"updated_at": "2020-12-06T16:58:24.000000Z",
"user": {
"id": 1,
"_id": "737ba284-424d-4b0d-8a56-2e845603f2ba",
"name": "Mohammed",
"username": "mohammed",
"email": "h4ck3r.x0#gmail.com",
"email_verified_at": null,
"avatar": "http://backend.mf.sa/storage/avatars/1607128001.jpg",
"location": null,
"gender": "male",
"bio": null,
"birthday": null,
"phone": null,
"created_at": "2020-12-05T00:26:09.000000Z",
"updated_at": "2020-12-05T00:26:41.000000Z"
}
},
{
"id": 19,
"post_id": 24,
"user_id": 2,
"emojy": "021-sad",
"created_at": "2020-12-06T16:58:36.000000Z",
"updated_at": "2020-12-06T16:58:36.000000Z",
"user": {
"id": 2,
"_id": "dfa19aa6-510b-4aaf-8475-4386da9de3d0",
"name": "Saleh",
"username": "saleh",
"email": "saleh#gmail.com",
"email_verified_at": null,
"avatar": "http://backend.mf.sa/storage/avatars/1607128041.jpg",
"location": null,
"gender": "male",
"bio": null,
"birthday": null,
"phone": null,
"created_at": "2020-12-05T00:27:02.000000Z",
"updated_at": "2020-12-05T00:27:21.000000Z"
}
}
],
"user": {
"id": 3,
"_id": "af65864b-f18a-4609-91db-336acbce1486",
"name": "Ali",
"username": "ali2323",
"email": "ali#gmail.com",
"email_verified_at": null,
"avatar": null,
"location": null,
"gender": "male",
"bio": null,
"birthday": null,
"phone": null,
"created_at": "2020-12-05T04:05:50.000000Z",
"updated_at": "2020-12-05T04:05:50.000000Z"
}
}
]
As you can see the first object in the array dosen't include the user data.
So what should i do $query->filterFollowingsOf($user); to include my data?
I think the with callback is used for modifying the query that selects the user data. Instead, try using a whereHas method that filters the related users.
$user = $request->user();
$followersPost = UserPost
::with('user')
->whereHas('user', function ($query) use ($user) {
$query->filterFollowingsOf($user);
})
->latest()
->get();
return $followersPost;
I'd also recommend using paginate() instead of get() for performance when there could be a significant number of posts.
Edit:
To get either your friend's posts or your posts, try:
$followersPost = UserPost
::with('user')
->whereHas('user', function ($query) use ($user) {
$query->filterFollowingsOf($user);
})
->orWhere('user_id', $user->id)
->latest()
->get();

How to modify array structure returned by eloquent in laravel

I currently have the below array structure that I get when running Bonus::with('users')->get()
I have tried adding the array and merging similar keys but it is not working. I tried using the helper methods provided in laravel but I don't seem to be able to get it working.
[
{
"id": 1,
"users_id": 1,
"bonus_type_id": 1,
"is_paid": 0,
"amount": "100.00",
"description": "desc",
"note": null,
"created_by": 2,
"last_modified_by": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"user": {
"id": 1,
"name": "test",
"email": "test#testing.com",
"email_verified_at": null,
"status": 1,
"created_at": "2019-07-18 11:41:35",
"updated_at": "2019-07-18 11:41:35",
"deleted_at": null
}
},
{
"id": 2,
"users_id": 1,
"bonus_type_id": 2,
"is_paid": 0,
"amount": "100.00",
"description": "desc",
"note": null,
"created_by": 2,
"last_modified_by": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"user": {
"id": 1,
"name": "test",
"email": "test#testing.com",
"email_verified_at": null,
"status": 1,
"created_at": "2019-07-18 11:41:35",
"updated_at": "2019-07-18 11:41:35",
"deleted_at": null
}
},
{
"id": 3,
"users_id": 2,
"bonus_type_id": 2,
"is_paid": 1,
"amount": "100.00",
"description": "desc",
"note": null,
"created_by": 2,
"last_modified_by": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"user": {
"id": 1,
"name": "another test",
"email": "another#testing.com",
"email_verified_at": null,
"status": 1,
"created_at": "2019-07-18 11:41:35",
"updated_at": "2019-07-18 11:41:35",
"deleted_at": null
}
}
]
I want the result to be something like that
[
{
user_id: 1,
name: "test",
bonuses: [
{
bonus_type_id: 1,
amount: 100,
is_paid: 0,
},
{
bonus_type_id: 2,
amount: 100,
is_paid: 0,
}
],
},
{
user_id: 2,
name: "another",
bonuses: [
{
bonus_type_id: 2,
amount: 100,
is_paid: 1,
},
]
}
]
You need to change your eloquent relationship. Define hasMany relationship function bonuses inside User model for bonuses table and use that to get the desired result like so:
User::with('bonuses')->get();
That way it will return results from users table and populate bonuses for each user.
makes sense?
You can get specific information with select subquery, if your relations are correctly set, this should work.
User::select('user_id','name','bonus_id')
->with(array('bonuses'=> function($query){
$query->select('bonus_type_id','amount','is_paid');
}))->get();

How to sort the collection on custom condition in laravel 5.7?

I have an api ready that returns the following json response.
Response:
{
"success": true,
"conversation": [{
"id": 37,
"type": "1",
"name": "Sonali",
"created_at": "2019-02-18 13:26:10",
"updated_at": "2019-02-18 20:32:54",
"unread_count": 2,
"chat": {
"id": 357,
"conversation_id": "23",
"type": "text",
"sender_id": "37",
"receiver_id": "39",
"data": "{\"text\":\"hello....\"}",
"delivered_at": "2019-02-20 13:25:27",
"seen_at": null,
"created_at": "2019-02-20 13:25:10",
"updated_at": "2019-02-20 13:25:27",
"sender_name": "Sonali"
}
},
{
"id": 38,
"type": "1",
"name": "Raviraj",
"created_at": "2019-02-18 20:23:55",
"updated_at": "2019-02-18 20:32:47",
"unread_count": 0,
"chat": {
"id": 354,
"conversation_id": "22",
"type": "text",
"sender_id": "39",
"receiver_id": "38",
"data": "{\"text\":\"hey....\"}",
"delivered_at": null,
"seen_at": null,
"created_at": "2019-02-20 13:24:35",
"updated_at": "2019-02-20 13:24:35",
"sender_name": "Nitesh Kesarkar"
}
},
{
"id": 27,
"type": "1",
"name": "Rakesh",
"created_at": "2019-02-01 10:48:19",
"updated_at": "2019-02-07 11:35:10",
"unread_count": 1,
"chat": {
"id": 358,
"conversation_id": "21",
"type": "text",
"sender_id": "27",
"receiver_id": "39",
"data": "{\"text\":\"hello\"}",
"delivered_at": "2019-02-20 13:25:27",
"seen_at": null,
"created_at": "2019-02-20 13:25:24",
"updated_at": "2019-02-20 13:25:27",
"sender_name": "Rakesh Patil"
}
}
]
}
This response consists of list of users and their associated last chat message for currently logged in user. I want to sort this collection according to the latest message first. How can I do that?
Sorting should be based on the chat.created_at field.
Expected Result:
{
"success": true,
"conversation": [
{
"id": 27,
"type": "1",
"name": "Rakesh",
"created_at": "2019-02-01 10:48:19",
"updated_at": "2019-02-07 11:35:10",
"unread_count": 1,
"chat": {
"id": 358,
"conversation_id": "21",
"type": "text",
"sender_id": "27",
"receiver_id": "39",
"data": "{\"text\":\"hello\"}",
"delivered_at": "2019-02-20 13:25:27",
"seen_at": null,
"created_at": "2019-02-20 13:25:24",
"updated_at": "2019-02-20 13:25:27",
"sender_name": "Rakesh Patil"
}
},
{
"id": 37,
"type": "1",
"name": "Sonali",
"created_at": "2019-02-18 13:26:10",
"updated_at": "2019-02-18 20:32:54",
"unread_count": 2,
"chat": {
"id": 357,
"conversation_id": "23",
"type": "text",
"sender_id": "37",
"receiver_id": "39",
"data": "{\"text\":\"hello....\"}",
"delivered_at": "2019-02-20 13:25:27",
"seen_at": null,
"created_at": "2019-02-20 13:25:10",
"updated_at": "2019-02-20 13:25:27",
"sender_name": "Sonali"
}
},
{
"id": 38,
"type": "1",
"name": "Raviraj",
"created_at": "2019-02-18 20:23:55",
"updated_at": "2019-02-18 20:32:47",
"unread_count": 0,
"chat": {
"id": 354,
"conversation_id": "22",
"type": "text",
"sender_id": "39",
"receiver_id": "38",
"data": "{\"text\":\"hey....\"}",
"delivered_at": null,
"seen_at": null,
"created_at": "2019-02-20 13:24:35",
"updated_at": "2019-02-20 13:24:35",
"sender_name": "Nitesh Kesarkar"
}
}
]
}
UPDATE :
Adding these lines worked as expected. Thanks #JCode
$sorted = $chats->sortByDesc('chat.created_at');
$chats = $sorted->values()->all();
You are looking for the sortBy() method.
This will of course work if your JSON output can be turned into a collection via collect()—in a perfect scenario, your chat messages would be a model in Laravel.

How can I hidden data in JSON if variable is empty

I got a some trouble in my Laravel application, in Search function, when I do search the result is
{
"data": [
{
"id": 2,
"user_id": 8,
"identity_number": "213918273",
"name": "Pekerja_2",
"gender_id": 1,
"date_of_birth": "1999-05-25",
"address": "Jalan Bandung Raya no 50",
"province_id": 32,
"city_id": 3273,
"district_id": 3273160,
"phone": "4232343432",
"image": null,
"created_at": "2018-01-11 10:59:54",
"updated_at": "2018-01-11 10:59:54",
"partner_id": null,
"skill": [
{
"id": 3,
"worker_id": 2,
"skill_id": 6,
"sub_skill_id": 18,
"created_at": "2018-01-15 13:06:48",
"updated_at": "2018-01-15 13:06:48",
"price": null,
"unit": null
}
]
},
{
"id": 3,
"user_id": 16,
"identity_number": "213918273",
"name": "Pekerja_3",
"gender_id": 1,
"date_of_birth": "1999-05-25",
"address": "Jalan Bandung Raya no 50",
"province_id": 32,
"city_id": 3273,
"district_id": 3273160,
"phone": "2345234234",
"image": null,
"created_at": "2018-01-15 13:06:48",
"updated_at": "2018-01-15 13:06:48",
"partner_id": null,
"skill": []
}
]
}
as you can see that "Skill" with id number 3 is empty, I want all in id number 3 is empty also.
My controller is :
$worker = Worker::with(['skill' => function($q) use ($request) {
$q->where('worker_skills.sub_skill_id', $request['sub_skill_id']);
}])->whereHas('skill');
And I want something like this :
{
"data": [
{
"id": 2,
"user_id": 8,
"identity_number": "213918273",
"name": "Pekerja_2",
"gender_id": 1,
"date_of_birth": "1999-05-25",
"address": "Jalan Bandung Raya no 50",
"province_id": 32,
"city_id": 3273,
"district_id": 3273160,
"phone": "2534234234",
"image": null,
"created_at": "2018-01-11 10:59:54",
"updated_at": "2018-01-11 10:59:54",
"partner_id": null,
"skill": [
{
"id": 3,
"worker_id": 2,
"skill_id": 6,
"sub_skill_id": 18,
"created_at": "2018-01-15 13:06:48",
"updated_at": "2018-01-15 13:06:48",
"price": null,
"unit": null
}
]
},
]
}
The point is, if "skill" variable is empty then data not show and vice versa.
Thankyou any help will appreciate, sorry for bad english
You can add a callback to your whereHas function with the same filter as the with function
$worker = Worker::with(['skill' => function($q) use ($request) {
$q->where('worker_skills.sub_skill_id', $request['sub_skill_id']);
}])
->whereHas('skill', function($q) use ($request) {
$q->where('worker_skills.sub_skill_id', $request['sub_skill_id']);
})
->get();
You can try this $worker = Worker:has('skill')->get();
Only worker that have at least one skill are contained in the collection

Categories