Laravel - Eloquent group by - laravel

When I use group by, the results get grouped but not all of them are returned. Here I have six results but I only get five results. So basically room_id = 17 gets the entry 103 and entry 106 is not returned.
Here is what I am doing:
$prices = $hotel->prices()->groupBy('room_id')->get();

There is a way of grouping the like you desire. You can use groupBy() on the collection eloquent returns when it executes the query. The trick is to groupBy() after the database retrieving. Check this for more info.
An example would look like this:
$prices = $hotel->prices()->get(); // Returns a Collection of results
$prices = $prices->groupBy('room_id'); // Grouped by room_id
This will result in a collection that looks like:
[
'39' => [
// 1 row
],
'40' => [
// 1 row
],
'17' => [
// 2 rows
],
.....
]
The keys of this array will represent the room_id. On every key is this array will be another array containing the rows with the specified room_id.
Hope this helps :)

Related

how to get 2 table data into single variable array in laravel?

i have 2 tables User and subadmin consider user have 3 columns and subadmin has 2 column i want to get 3+2 (5 column) data into a single veriable array
the technique i want to use is that in user table i have id which is same in subadmin table with sub_admin_id(column) how i can use eloquent model to first link id with sub_admin_id and then into a single query get 5 column in single veriable array
here i am using to get data
$subadmindata = User::find($id)->get(); // [column1 ,column2 ,column3 ]
$subadmindata1 = SubAdmin::find($id)->get(); // [column1 ,column2 ]
output should be
$data = // [column1 ,column2 ,column3 , column4 ,column5 ]
note i dont want to use array merge or combine method i want to use eloquent model for my learning
you could use concat like this
$subadmindata = User::find($id)->get();
$subadmindata1 = SubAdmin::find($id)->get(); // it will return array of collections
$data = $subadmindata->concat($subadmindata1);
Notice when you use get after find it stop it's jobs so there is no need to find here
get() method will give you a collection not array, so you can merge two collection as follows.
$subadmindata = User::find($id)->get();
$subadmindata1 = SubAdmin::find($id)->get();
$data = $subadmindata->merge($subadmindata1);
You can't use find with get(Assuming that you need a one result not all of the users). Try this. But looks like you need build the relationships correctly first. Anyway, quick answer is below.
$userCols = User::select('column1','col2','col3')->find($id);
$subAdminCols = SubAdmin::select('col4','col5')->find($id);
$cols = array_merge($userCols->toArray(), $subAdminCols->toArray());
try this
in user model
public function subadmin(){
return $this->hasOne(SubAdmin::class,'sub_admin_id');
}
in controller
$sub_admins = User::find($id);
dd($sub_admins->subadmin->sub_admin_id)
you can use php ... operator to to push data
example like this
$subadmindata = User::find($id)->get()->toArray(); // [column1 ,column2 ,column3 ]
$subadmindata1 = SubAdmin::find($id)->get()->toArray(); // [column1 ,column2 ]
array_push($subadmindata, ...$subadmindata1);
return $subadmindata
ref link https://wiki.php.net/rfc/spread_operator_for_array

Using LINQ to SELECT the SUM() of a subquery

I am trying to learn how to use LINQ to perform a query that yields the same result as this:
SELECT (
SELECT SUM(point)
FROM communitymemberpointfeature
WHERE communitymemberpointfeature.communitymemberid = communitymember.id
) AS points, communitymember.*
FROM communitymember
After browsing around the Internet, I constructed the following statement:
var list = (from pointFeature in communityMemberPointFeatureList
join member in communityMemberList on pointFeature.CommunityMemberId equals member.Id
group pointFeature by new { pointFeature.CommunityMemberId }
into grouping
select new
{
grouping,
points = grouping.Sum(row => row.Point)
}).ToList();
But this yielded a result like
[
{
points:7200,
grouping:[
{Id:1,Point:5000,FeatureId:1,CommunityMemberId:1},
{Id:2,Point:2200,FeatureId:1,CommunityMemberId:1},
],
}
...
]
What I really want is a result set like:
[
{points:7200,CommunityMemberId:1,firstname:'john',lastname:'blah' ....},
...
]
Can someone tell me what I did wrong?
Edit after comment added to the end
I can imagine you have problems translating your SQL into LINQ. When trying to write LINQ statements it is usually a lot easier to start from your requirements, instead of starting from a SQL statement.
It seems to me that you have a table with CommunityMembers. Every CommunityMember has a primary key in property Id.
Furthermore, every CommunityMember has zero or more CommunityMemberPointFeatures, namely those CommunityMemberPointFeatures with a foreign key CommunityMemberId that equals the primary key of the CommunityMember that it belongs to.
For example: CommunityMember [14] has all CommunityMemberPointFeatures that have a value CommunityMemberId equal to 14.
Requirement
If I look at your SQL, it seems to me that you want to query all CommunityMembers, each with the sum of property Point of all CommunityMemberPointFeatures of this CommunityMember.
Whenever you want to query "items with their zero or more subitems", like "Schools with their Students", "Customers with their Orders", "CommunityMembers with their PointFeatures", consider using GroupJoin.
A GroupJoin is in fact a Left Outer Join, followed by a GroupBy to make Groups of the Left item with all its Right items.
var result = dbContext.CommunityMembers // GroupJoin CommunityMembers
.GroupJoin(CommunityMemberPointFeatures, // With CommunityMemberPointFeatures
communityMember => communityMember.Id, // from every CommunityMember take the Id
pointFeature => pointFeature.CommunityMemberId, // from every CommunityMemberPointFeature
// take the CommunityMemberId
// Parameter ResultSelector: take every CommunityMember, with all its matching
// CommunityMemberPointFeatures to make one new object:
(communityMember, pointFeaturesOfThisCommunityMember) => new
{
// Select the communityMember properties that you plan to use:
Id = communityMember.Id,
Name = communityMember.Name,
...
// From the point features of this CommunityMember you only want the sum
// or property Point:
Points = pointFeaturesOfThisCommunityMember
.Select(pointFeature => pointFeature.Point)
.Sum(),
// However, if you want more fields, you can use:
PointFeatures = pointFeaturesOfThisCommunityMember.Select(pointFeature => new
{
Id = pointFeature.Id,
Name = pointFeature.Name,
...
// not needed, you know the value:
// CommunityMemberId = pointFeature.CommunityMemberId,
})
.ToList(),
});
Edit after comment
If you want, you can omit Selecting the values that you plan to use.
// Parameter ResultSelector:
(communityMember, pointFeaturesOfThisCommunityMember) => new
{
CommunityMember = communityMember,
PointFeatures = pointFeaturesOfThisCommunityMember.ToList(),
),
However, I would strongly advise against this. If CommunityMember [14] has a thousand PointFeatures, then every PointFeature will have a foreign key with a value 14. So you are transporting this value 14 1001 times. What a waste of processing power, not to mention all the other fields you plan not to use.
Besides: if you do this you violate against information hiding: whenever your tables changes internally, the result of this function changes. Is that what you want?

how to use increment function in laravel

i am using DB to store values in database.
i have "course fees" column i what to "increment" the "course_fees" value in column.
for example
DB::table('student')->where('registration_id','=', $request->registration_id)->increment(['course_fees' =>$request->course_fees]);
this code increment the inserted value
how can i modified below code for increment "course_fees" value like above
DB::table('student')->where('registration_id','=', $request->registration_id)->update(['payment_date' => $request->payment_date,'balance_fees' => $request->balance_fees,'course_fees' =>$request->course_fees]);
You cannot use this method to increment multiple fields. You can use:
$studentQuery = DB::table('student')->where('registration_id','=', $request->registration_id);
(clone $studentQuery)->increment('payment_date',$request->payment_date);
(clone $studentQuery)->increment('balance_fees', $request->balance_fees);
(clone $studentQuery)->increment('course_fees', $request->course_fees);
but this way you will run 3 database queries to update.
But if you are sure there is exactly single record found for registration_id you can do it like this:
$student = DB::table('student')->where('registration_id','=', $request->registration_id)->first();
$student->update([
'payment_date' => $student->payment_date + $request->payment_date,
'balance_fees' => $student->balance_fees + $request->balance_fees,
'course_fees' => $student->course_fees + $request->course_fees
]);
EDIT
If you want to increment only course_fees column and want to update other 2 columns from input you can use:
DB::table('student')->where('registration_id','=', $request->registration_id)
->increment('course_fees' , $request->course_fees, [
'payment_date' => $request->payment_date,
'balance_fees' => $request->balance_fees
])
This is documentation about increment/decrement methods.
increment()/decrement() can take 3 parameters: $column, $amount, $extra.
$column is the field that you want to increment
$amount is by how much you want to increment the field by
$extra is an array of attributes that you also want to update in the query.
If you don't pass an amount the default for $amount is 1.
To achieve what you're after you could do:
DB::table('student')
->where('registration_id', $request->registration_id)
->increment('course_fees', $request->course_fees, [
'payment_date' => $request->payment_date,
'balance_fees' => $request->balance_fees,
]);

Can we get the total record count and the first record only in the same eloquent query?

Can we get the total record count and the first record only in the same eloquent query?
I know we can get the total records via below eloquent queries:
1. Model::count();
2. Collection Method
Model::all()->count();
And we can get the first record like this:
Model::first();
I have one solution for the same i.e.
$data = Model::all();
1. $count = count($data);
2. $count = $data->count();
And for the first row/data
1. $firstRecord = $data[0];
2. $firstRecord = $data->first();
When you create a query, Laravel under the hood, creates a new instance of the query builder with the method newQuery(), this query can be reused as much times as you want
$query = Model::where('...')->whereHas('...')->orderBy('...');
[
'count' => $query->count(),
'collection' => $query->get(),
'first' => $query->first()
]
Something similar happens with the LengthAwarePaginator's paginate() method. Have a look at the source code.

Laravel Eloquent querying pivot table not unique

For some reason I don't get the expected result when doing the following:
$cars = Car::query();
$cars->whereIsVisible(true);
# output: $list
// [2016-01-16 09:30:04] local.INFO: array (
// 0 => 5,
// 1 => 7,
// 2 => 9,
// 3 => 3,
// )
$cars->whereHas('specifications', function($query) use ($list) {
$query->whereIn('id', ($list));
});
$cars->get();
What I expect is that I get only cars that have all the specifications that are inside that $list, but that's not correct. Even when I fill in more specifications, I get a bigger result. So there goes something wrong.
I'm used to Eloquent, so I suck in queries. But this is the Query:
select * from "cars" where "cars"."deleted_at" is null
and "is_visible" = true
and (select count(*)
from "specs" inner join "car_specs"
on "specs"."id" = "car_specs"."facility_id"
where "car_specs"."car_id" = "cars"."id"
and "id" in (5, 7, 9 ,3)) >= 1
Anyone see where it goes wrong? And how to fix it?
According to https://laravel.com/docs/5.1/eloquent-relationships#querying-relations
whereHas just checks that you have cars with the provided specifications, not that it returns those cars that match your specifications.
I think you should use where directly.

Resources