Laravel where also returns empty results - php

I'm using Laravel 4 to get all the persons that have a score for a certain event
This is the query i'm using
$event = Person::with(array('eventscore' => function($q){
$q->where('id', 3);
}))->get();
The problem is that it's also returning the persons that don't have a score in the eventscore table.
This is the output
Is there any way that i can return only the persons that have a score?
Thanks!

with() will not limit the Persons returned, it will only limit eventscores. If you want only Persons that have an event score, you use has or whereHas.
$event = Person::whereHas('eventscore', function($q) {
$q->where('id', 3);
})->get();

Related

How I can get distinct records from laravel table using elequent model?

I have to fetch distinct records based on the entity ID . I have tried this but it is not working
User::where('id',$id)->with(['userRoleEntity' => function($q) { $q->distinct('entityId'); }])->first();
I should get two records in the user entity array but I am getting 3. How I can fix this ? thanks in advance
the value in the square should not be there https://prnt.sc/qkamdi
distinct method not support to pass an parameter, you need to select a field and distinct
User::where('id',$id)->
with(['userRoleEntity' => function($q) {
$q->select('entityId')->distinct();
}])->first();
or
Try this one:
User::where('id',$id)->
with(['userRoleEntity' => function($q) {
$q->groupBy('entityId');
}])->first();

Sum of column in where clause in laravel eloquent

I have a FamilyMember model and a SubscriptionCharge model, SubscriptionCharge store charges of multiple months of each family member.
I have to select members whos sum of charges greater than a specific amount.
$members=FamilyMember::whereHas('subscription_charge', function ($qq) {
$qq->where(); // how to check sum of column 'amount' in where
})->get();
How to check the sum of column 'amount' in a where condition
Based on your comment, Updated Answer
$memeber = FamilyMember::query()
->join(DB::raw('("SELECT subscription_charge.family_member_id, SUM(subscription_charge.amount) as total_charges FROM subscription_charge GROUP BY subscription_charge.family_member_id HAVING SUM(subscription_charge.amount) >
AMOUNT_YOU_WANT") as sub_table'), function($join) {
$join->on('sub_table.family_member_id', '=', 'family_member.id');
})->get();
Note: Not tested
I think you might be able to do something like this. (I'm at the airport so unable to test it.)
$members=FamilyMember->join(DB::raw('(SELECT family_member_id, SUM(amount) AS sum_of_charges
FROM subscription_charge
WHERE family_member_id = x
GROUP BY family_member_id
// (or HAVING family_member_id = x ?)
) charges'),
function($join)
{
$join->on('FamilyMember.id', '=', 'charges.family_member_id');
})
->select(
'FamilyMember.id',
'charges.sum_of_charges'
)
->where('sum_of_charges', '>', 'Y')
})->get();

How to get parents data that only has a child data in laravel

I'm trying to get all the data from the parent that only has a child. Please see my code below.
$customers = Customer::with(['items' => function($query){
return $query->where('status', 2);
}])->get();
dd($customers);
But the code above returns all the customer. By the way, I'm using laravel 4.2.
Items Table:
Customer Table:
with() is for eager loading. That basically means, along the main model, Laravel will preload the relationship(s) you specify. This is especially helpful if you have a collection of models and you want to load a relation for all of them. Because with eager loading you run only one additional DB query instead of one for every model in the collection.
has() is to filter the selecting model based on a relationship. So it acts very similarly to a normal WHERE condition. If you just use has('relation') that means you only want to get the models that have at least one related model in this relation.
e.g :
$users = Customer::has('items')->get();
// only Customer that have at least one item are contained in the collection
whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.
e.g
$users = Customer::whereHas('items', function($q){
$q->where('status', 2);
})->get();
// only customer that have item status 2
Adding group by to calculating sum
this is another example from my code :
Customer::select(['customer.name', DB::raw('sum(sale.amount_to_pay) AS total_amount'), 'customer.id'])
->where('customer.store_id', User::storeId())
->join('sale', 'sale.customer_id', '=', 'customer.id')
->groupBy('customer.id', 'customer.name')
->orderBy('total_amount', 'desc')
->take($i)
->get()
in your case :
Customer::select(['customer_id', DB::raw('sum(quantity) AS total')])
->whereHas('items', function ($q) {
$q->where('status', 2);
})
->groupBy('customer_id')
->get();
whereHas() allow you to filter data or query for the related model in your case
those customer that have items and it status is 2
afetr getting data we are perform ->groupBy('customer_id')
The GROUP BY statement is often used with aggregate functions (COUNT, MAX, MIN, SUM, AVG) to group the result-set by one or more columns.
select(['customer_id', DB::raw('sum(quantity) AS total')]) this will select customer id and calculate the sum of quantity column
You should use whereHas not with to check child existence.
$customers = Customer::whereHas('items', function($query){
return $query->where('status', 2);
})->get();
dd($customers);
I assume you already defined proper relationship between Customer and Item.
You should try this:
$customers = Customer::whereHas('items', function($query){
$query->where('status', 2);
})->get();
dd($customers);
Customer::select(['items.customer_id',DB::raw('count(items.id) AS total_qty')])
->join('items', 'items.user_id', '=', 'customer.customer_id')
->groupBy('items.customer_id')
->havingRaw('total_qty > 2')
->get();
OR
$data=DB::select("select `items`.`customer_id`, count(items.id) AS total_qty
from `customers`
inner join `items`
on `items`.`customer_id` = `customers`.`customer_id`
group by `items`.`customer_id` having total_qty >= 2");
correct table name and column name.

List conversation between 2 users in the correct order

I want to create a chat system on which i could list all the chats between specific 2 persons
I have 2 tables users and chats
my chats table have 3 columns - user_id, friend_id and chat
my User.php model file is like this
public function chats() {
return $this->hasMany('App\Chat');
}
For eg:
I want to list all the chat between user 1 and 3 without changing the order of the conversation
I can simply do it by doing $chats = Auth::user()->chats->where('friend_id', '=', $id); but this will only give the authenticated (which is user 1 or 3) users chats. But I want the conversation between both of them.
So I have found an alternate way to do that by
$first = Chat::all()->where('user_id', '=', Auth::user()->id)->where('friend_id', '=', $id);
$second = Chat::all()->where('user_id', '=', $id)->where('friend_id', '=', Auth::user()->id);
$chats = $first->merge($second);
But this way has some problems. This will not get the chats in the correct order. I think it is impossible to order it correctly.
So my question is how can I list the conversation between two persons in the correct order easily?
If you want more details about my problem you can just ask.
You should be able to do it in one query with parameter grouping, rather than executing two separate queries and then merging them.
Chat::where(function ($query) use ($id) {
$query->where('user_id', '=', Auth::user()->id)
->where('friend_id', '=', $id);
})->orWhere(function ($query) use ($id) {
$query->where('user_id', '=', $id)
->where('friend_id', '=', Auth::user()->id);
})->get();
This might also return your results in the correct order, just because without any sort criteria specified, databases will often return rows in the order they were inserted. However, without adding something to your chat table to sort by, (either a timestamp or an autoincrement id), there's no way to guarantee it.
Try like this
$first = Chat::all()->where('user_id', '=', Auth::user()->id)
->where('friend_id', '=', $id)->get();
$second = Chat::all()->where('user_id', '=', $id)
->where('friend_id', '=', Auth::user()
->id)->get();
$chats = $first->merge($second)
->sortBy('created_at');//created_at is timing added change if other
First of all, you should not do all() before filtering. This is bad because fetches all the table data and then does the filtering in PHP.
You should consider doing this:
In your migration:
Schema::create("chat", function (Blueprint $table) {
//Other creation lines
$table->timestamps();
})
Then in your chat model:
public function scopeInvolvingUsers($query, $userId,$friendId) {
return $query->where([ ["user_id",$userId],["friend_id",$friendId] ])
->orWhere([ ["user_id",$friendId],["friend_id",$userId] ]);
}
Then you can do the following:
$chats = Chat::involvingUsers(\Auth::id(),$otherId)->latest()->get();
Note that latest or earliest requires the timestamps to be present on the table.
I will add timestamps in chat table which will ensure the order.
To add timestamp into chat table just add
$table->timestamps();
and the you can select the chat related to the user and sort it by created_at.
In laravel 5.3+ use
Chats::where(['user_id', '=', Auth::id()], ['friend_id', '=', $id])->orWhere(['user_id', '=', $id], ['friend_id', '=', Auth::id()])->sortBy('created_at');
Chat::whereIn('user_id', [$id, Auth->user()->id])
->whereIn('friend_id', [$id, Auth->user()->id])->get();

Laravel4 ->whereIn: get all keywords per event

I have the following query:
public function getEventsByKeywordIds($data){
//Query events by dates
$query = DB::table('events')
->join('events_dates', function($join) use ($data){
$join->on('events.id', '=', 'events_dates.event_id')
->where('events_dates.start_date', "<=", date_format(date_create($data['date_end']), "Y-m-d"))
->where('events_dates.end_date', '>=', date_format(date_create($data['date_start']), "Y-m-d"));
});
//Query events by keywords
$query = $query->join('events_keywords', function($join) use ($data){
$join->on('events.id', '=', 'events_keywords.event_id');
})->whereIn('events_keywords.keyword_id', $data["keyword_ids"]);
//Query places
$query = $query->join('places', function($join) use ($data){
$join->on('events.place_id', '=', 'places.id');
});
//Set offset and limit
$query = $query
->take($data['limit'])
->offset($data['offset'])
->orderBy('events_dates.start_date', 'ASC')
->orderBy('events.name', 'ASC')
->groupBy('events.id');
$events = $query->get();
return $events;
}
I am interested in the part that mentions "Query events by keywords".
events_keywordsis a many-to-many table, linking event id's and keyword id's to each other.
The requirement exists to return the keywords per event to the client, but so far the query only returns 1 keyword per event that it returns.
Note: $data["keyword_ids"]is an array of keywords sent from the client, because only events related to certain keywords should be returned.
Do you have any suggestions to adapt this query in a simple way to meet the requirement?
Edit: what I require is actually the keyword names, which is stored in the keyword table (not the many-to-many.
I solved the problem by creating a many to many relationship through Laravel's belongsToMany relation.
foreach($events as $event){
$temp_event = EventModel::find($event->id);
$event->keywords = $temp_event->keywords;
}
return $events;
This is not the most efficient solution I'm sure, but it works.

Categories