Laravel JSON format is coming wrong by using groupBy function - laravel

I have created an API resource which is returning selected subject and categories of the specific tutor by using groupBy method,
the issue is, groupBy method is not sending the response as I am expecting.
Please find the current and expected response below,
Current API response
"Web Design": [
{
"id": 542,
"name": "WordPress",
"category_name": "Web Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 70,
}
},
{
"id": 542,
"name": "WordPress",
"category_name": "Web Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 70,
}
}
],
"Graphic Design": [
{
"id": 547,
"name": "Photoshop",
"category_name": "Graphic Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 71,
}
},
{
"id": 548,
"name": "WordPress",
"category_name": "Graphic Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 71,
}
}
]
groupBy Function:
$subjects = $this->tutor->subjects->map(function($subject){
$subject->category_name = SubjectCategory::find($subject->pivot->subject_category_id)->name;
return $subject;
});
$subjectData = $subjects->groupBy('category_name');
Expected API response
"category": "Web Design",
"subjects": [
{
"id": 542,
"name": "WordPress",
"category_name": "Web Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 70,
}
},
{
"id": 542,
"name": "WordPress",
"category_name": "Web Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 70,
}
}
],
"category": "Graphic Design",
"subjects": [
{
"id": 547,
"name": "Photoshop",
"category_name": "Graphic Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 71,
}
},
{
"id": 548,
"name": "WordPress",
"category_name": "Graphic Design",
"pivot": {
"tutor_id": 4,
"subject_id": 542,
"subject_category_id": 71,
}
}
]
Please find the given migrations for subject categories, subject & subject category table.
Miigration: SubjectCategories
Schema::create('subject_categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug');
$table->integer('parent_id')->nullable();
$table->unsignedTinyInteger('is_deleted')->default(SubjectCategory::IS_DELETED);
$table->timestamps();
});
Migration: CreateSubjectsTable
Schema::create('subjects', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug');
$table->integer('isActive');
$table->timestamps();
});
Migration: CreateSubjectSubjectCategoryTable
Schema::create('subject_subject_category', function (Blueprint $table) {
$table->increments('id');
$table->integer('subject_id')->unsigned();
$table->integer('subject_category_id')->unsigned();
});
Schema::table('subject_subject_category', function($table) {
$table->foreign('subject_id')->references('id')->on('subjects');
$table->foreign('subject_category_id')->references('id')->on('subject_categories');
});
Thanks in advance for help.

The Laravel response is exactly what it's supposed to be when using the groupBy() method on a Collection instance.
Also, your "expected" JSON response is invalid. You cannot use the same property name multiple times, as you will only end up with the last defined values (e.g., the last category property would overwrite the previous category property -- same with subjects). You would need to at the very least group them into their own arrays.
[
"category": "Web Design",
"subjects": [...]
],
[
"category": "Graphic Design",
"subjects": [...]
],
This output could be achieved through some simple formatting of your query results.
$formatted_response = [];
foreach ($subjectData as $category => $subjects) {
$formatted_response[] = [
'category' => $category,
'subjects' => $subjects
];
}
return response()->json($formatted_response);
I hope this helps and good luck!

Related

jenssegers/laravel-mongodb One to Many (with reference) relationship doesn't work at all

I have 2 models created with jenssegers/laravel-mongodb package.
<?php
class CronJob extends Model {
protected $connection = 'mongodb';
protected $collection = 'cronjobs';
protected $primaryKey = '_id';
protected $dates = [
'created_at',
'updated_at'
];
public function details()
{
return $this->hasMany(CronJobDetail::class, 'parent_id', '_id');
}
}
class CronJobDetail extends Model {
protected $connection = 'mongodb';
protected $collection = 'cronjobsdetails';
protected $primaryKey = '_id';
protected $dates = [
'created_at',
'updated_at'
];
public function job()
{
return $this->belongsTo(CronJob::class, 'parent_id', '_id');
}
When I call CronJobDetail::first()->job I get the parent CronJob object successfully. But when I do the same as inverse like CronJob::first()->details, I get empty collection for some reason. Why isn't it working as expected?
Here's some example data for better insight:
CronJob document
{
"_id": {
"$oid": "6308cd0b2b290000c100086b"
},
"name": "Deneme-2022-08-26 16:39:23 (2)",
"job": "assignproduct",
"job_count": 2,
"product_id": "630869372b290000c1000865",
"product_name": "Deneme",
"tax_rate": 18,
"organisation": 111,
"created_by": 4,
"created_by_name": "Çağlar TUFAN",
"price": 150,
"currency": "TL",
"created_at": "2022-08-26 16:39:23",
"updated_at": "2022-08-26 16:39:23"
}
CronJobDetails documents
{
"_id": {
"$oid": "6308cd0b2b290000c100086b"
},
"name": "Deneme-2022-08-26 16:39:23 (2)",
"job": "assignproduct",
"job_count": 2,
"product_id": "630869372b290000c1000865",
"product_name": "Deneme",
"tax_rate": 18,
"organisation": 111,
"created_by": 4,
"created_by_name": "Çağlar TUFAN",
"price": 150,
"currency": "TL",
"created_at": "2022-08-26 16:39:23",
"updated_at": "2022-08-26 16:39:23"
},
{
"_id": {
"$oid": "6308cd0b2b290000c100086d"
},
"job": "assignproduct",
"email": "erhan#w3.com.tr",
"product_id": "630869372b290000c1000865",
"product_name": "Deneme",
"organisation": 111,
"status": 0,
"created_by": 4,
"created_by_name": "Çağlar TUFAN",
"price": 150,
"currency": "TL",
"created_at": "2022-08-26 16:39:23",
"updated_at": "2022-08-26 16:39:23",
"name": "Deneme-2022-08-26 16:39:23 (2)",
"parent_id": {
"$oid": "6308cd0b2b290000c100086b"
}
}

Laravel nested eloquent relationships using model

I am trying to getting the more sorted object as output using laravel eloquent relationships
Section::with(['fieldTypes','fields'=>
function ($query) use ($id) {
$query->where('user_id', '=', $id);
},
'fields.fieldType'=> function ($query) {
$query->select('id','type','url','icon');
}])->get();
Output
"fields": [
{
"id": 1,
"user_id": 1,
"field_type_id": 1,
"section_id": 3,
"title": "Facebook",
"value": "inderjit",
"order": 1,
"field_type": {
"id": 1,
"type": "facebook",
"url": "https://www.facebook.com/"
}
}
]
I want output like this . I want to merge 2 objects as one
"fields": [
{
"id": 1,
"user_id": 1,
"field_type_id": 1,
"section_id": 3,
"title": "Facebook",
"value": "inderjit",
"order": 1,
"type": "facebook",
"url": "https://www.facebook.com/"
}
]
Something like this. You can add a method in your model where you trigger a leftJoin. Then you have the fields of the relation in the model.
public function scopeJoinWithFieldTypes($query)
{
return $query->leftJoin("field_types", "field_type.id", "=", "fields.id");
}

How to display 0 if no record in laravel

I have this query. Currently, this displays the status_count for the logged users. I want to update this query to display all the statuses from the status table and if the logged user has no record for any statuses to display status_count as 0.
$orderStatistics = OrderHeader::select('status.id', 'status.name', 'status.description', 'status.type', 'status.code',
DB::raw('order_status,count(*) as status_count'))
->leftjoin('status', 'status.code', '=', 'order_header.order_status')
->orderBy('status.id')
->groupBy('order_status')
->where([['order_header.user_id', auth()->user()->id], ['status.type', 'ORD']])
->get();
Let's say the status table has one new record TST where type is equal to ORD. And order_header table does not contain any record for TST for the currently logged user.
Current Response:
"data": [
{
"id": 11,
"name": "note",
"description": "note",
"type": "ORD",
"code": "NTE",
"order_status": "NTE",
"status_count": 2
},
{
"id": 12,
"name": "approved",
"description": "approved",
"type": "ORD",
"code": "APR",
"order_status": "APR",
"status_count": 2
},
]
How I want is:
"data": [
{
"id": 11,
"name": "note",
"description": "note",
"type": "ORD",
"code": "NTE",
"order_status": "NTE",
"status_count": 2
},
{
"id": 12,
"name": "approved",
"description": "approved",
"type": "ORD",
"code": "APR",
"order_status": "APR",
"status_count": 2
},
{
"id": 13,
"name": "test",
"description": "test",
"type": "ORD",
"code": "TST",
"order_status": "TST",
"status_count": 0
},
]
How to update my query to achieve this using IFNULL. Thanks in advance.
Assuming you have set up your model relations correctly, you should be able to do this by chaining:
withCount('status')
Docs: https://laravel.com/docs/8.x/eloquent-relationships#counting-related-models

How to retrieve Json data type data in SQL using a where condition in LARAVEL

Question : How to retrieve Json data type data in SQL using a where condition in LARAVEL?
I want to display all the order that contains order->Product->user->id === 1
{
"currentUserID": 1,
"currentUserName": "Mohamed Naalir",
"order": [
{
"id": 26,
"Product": [
{
"id": 4,
"name": "Araliya Rice",
"desription": "Araliya Rice",
"salePrice": 500,
"category": "Rice",
"user": {
"id": 1,
"name": "Mohamed Naalir",
}
}
],
},
{
"id": 27,
"Product": [
{
"id": 2,
"name": "white sugar",
"desription": "aaa",
"salePrice": 100,
"category": "Sugar",
"user": {
"id": 5,
"name": "Mohamed Sharaf",
}
}
],
}
]
}
json where clauses
$orders = DB::table('orders')
->whereJsonContains('Product', [['user' => ['id' => 1]]])
->get();

Laravel Eloquent - Get Eloquent Relationship Model Data From nested Relationship

I have 3 models like this-
User
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $fillable = [
'profile_picture',
'first_name',
'last_name',
'email',
'cell_no',
'website',
'date_of_birth',
'social_security_number_p1',
'social_security_number_p2',
'social_security_number_p3',
'address',
'location_latitude',
'location_longitude',
'password',
'user_type',
'is_enabled'
];
protected $hidden = [
'password',
'remember_token',
'id',
'user_type',
'is_enabled',
'created_at',
'updated_at'
];
public function advertisement()
{
return $this->hasMany('App\Advertisement', 'user_id');
}
}
Advertisement
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Auth;
class Advertisement extends Model
{
protected $fillable = [
'user_id',
'category_id',
'sub_category_id',
'title',
'price',
'description',
'address',
'location_lat',
'location_lon',
'is_active',
'deleted_at'
];
public function User()
{
return $this->belongsTo('App\User','user_id', 'id');
}
public function Offer()
{
return $this->hasMany('App\Offer', 'add_id', 'id');
}
}
Offer
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Offer extends Model
{
protected $fillable = [
'add_id',
'user_id',
'price',
'message'
];
public function User()
{
return $this->hasOne('App\User','user_id','id');
}
public function Advertisement()
{
return $this->hasOne('App\advertisement','add_id','id');
}
}
I want to get advertisements with offer and offers with offer sender (user).
So, I am doing something like this-
return Advertisement::with('AdvertisementImages')
->with('Offer')
->with('User')
->where('user_id', Auth::user()->id)
->get();
And getting this-
[
{
"id": 1,
"user_id": 16,
"title": "123asd",
"price": 123,
"description": "asd asd asd ",
"address": "Dhaka University Campus, Dhaka, Dhaka Division, Bangladesh",
"location_lat": 23.73,
"location_lon": 90.39,
"total_views": "110",
"avg_rating": "4.0000",
"is_reviewed": 0,
"is_offer_sent": 1,
"advertisement_images": [
{
"image_name": "16-68261.jpg"
},
{
"image_name": "16-34746.JPG"
},
{
"image_name": "16-79570.jpg"
}
],
"offer": [
{
"id": 1,
"add_id": 1,
"user_id": 9,
"price": 123,
"message": "asd ad asdasd ",
"created_at": "2016-08-11 02:22:43",
"updated_at": "2016-08-11 02:22:43"
},
{
"id": 2,
"add_id": 1,
"user_id": 15,
"price": 43,
"message": "as dfasd ",
"created_at": "2016-08-11 02:24:04",
"updated_at": "2016-08-11 02:24:04"
},
{
"id": 3,
"add_id": 1,
"user_id": 16,
"price": 23,
"message": "hgf",
"created_at": "2016-08-11 02:25:31",
"updated_at": "2016-08-12 01:37:42"
}
],
"user": {
"profile_picture": "",
"first_name": "Ne",
"last_name": "Ajgor",
"cell_no": null,
"email": "ajgor#me.com",
"website": "",
"date_of_birth": "0000-00-00",
"social_security_number_p1": "",
"social_security_number_p2": "",
"social_security_number_p3": "",
"address": "",
"location_latitude": 0,
"location_longitude": 0
}
}
]
So, it is wrong. I am getting user from Advertisement.
But I like to have user from Offer.
So, I need to have something like this-
[
{
"id": 1,
"user_id": 16,
"title": "123asd",
"price": 123,
"description": "asd asd asd ",
"address": "Dhaka University Campus, Dhaka, Dhaka Division, Bangladesh",
"location_lat": 23.73,
"location_lon": 90.39,
"total_views": "110",
"avg_rating": "4.0000",
"is_reviewed": 0,
"is_offer_sent": 1,
"advertisement_images": [
{
"image_name": "16-68261.jpg"
},
{
"image_name": "16-34746.JPG"
},
{
"image_name": "16-79570.jpg"
}
],
"offer": [
{
"id": 1,
"add_id": 1,
"user_id": 9,
"price": 123,
"message": "asd ad asdasd ",
"created_at": "2016-08-11 02:22:43",
"updated_at": "2016-08-11 02:22:43",
"user": {
"profile_picture": "",
"first_name": "Me",
"last_name": "Ajgor",
"cell_no": null,
"email": "ajgor#me.com",
"website": "",
"date_of_birth": "0000-00-00",
"social_security_number_p1": "",
"social_security_number_p2": "",
"social_security_number_p3": "",
"address": "",
"location_latitude": 0,
"location_longitude": 0
}
},
{
"id": 2,
"add_id": 1,
"user_id": 15,
"price": 43,
"message": "as dfasd ",
"created_at": "2016-08-11 02:24:04",
"updated_at": "2016-08-11 02:24:04",
"user": {
"profile_picture": "",
"first_name": "Ne",
"last_name": "Ajgor",
"cell_no": null,
"email": "ajgor#me.com",
"website": "",
"date_of_birth": "0000-00-00",
"social_security_number_p1": "",
"social_security_number_p2": "",
"social_security_number_p3": "",
"address": "",
"location_latitude": 0,
"location_longitude": 0
}
},
{
"id": 3,
"add_id": 1,
"user_id": 16,
"price": 23,
"message": "hgf",
"created_at": "2016-08-11 02:25:31",
"updated_at": "2016-08-12 01:37:42",
"user": {
"profile_picture": "",
"first_name": "Je",
"last_name": "Ajgor",
"cell_no": null,
"email": "ajgor#me.com",
"website": "",
"date_of_birth": "0000-00-00",
"social_security_number_p1": "",
"social_security_number_p2": "",
"social_security_number_p3": "",
"address": "",
"location_latitude": 0,
"location_longitude": 0
}
}
]
}
]
Can anyone please help me, what I need to call?
Thanks in advance for helping.
I have solved it like this-
Advertisement::with('AdvertisementImages')
->with('Offer','Offer.User')
->where('user_id', Auth::user()->id)
->has('Offer')
->get();

Resources