how to to make eloquent scope with whereHas like sql query below? - mysql

how to to make eloquent scope with whereHas like sql query below
table Property(id, title, slug, category_id, location_id,image)
table Category(id, name, slug)
table City ( id, name, slug)
The simple sql query that i need
Select * from property
join category on property.category_id=category.id
join city on property.location_id = city.id
where category.name = $query and city.name=$query
I want to make the eloquent scope in the Property Model

This is easy with relationships.
Based on your query, let's say this is your Property model:
class Property extends Model
{
public function category()
{
return $this->belongsTo(Category::class);
}
public function city()
{
return $this->belongsTo(City::class, 'location_id');
}
Now I can write my Eloquent query like this:
$query = 'Example';
$properties = Property::where('name', $query)
->whereHas('category', function (Builder $builder) use ($query) {
$builder->where('name', $query);
})->get();
Please note that Builder is imported from Illuminate\Database\Eloquent\Builder. You can also add with('category', 'city') to the query above in order to eager load those relationships.

Related

laravel eloquent subquery same table different columns

i am trying to re-construct a working mysql query (or something better with the same result) in laravel eloquent. My db looks like this:
I have a words table with columns id and name.
I have a pivot table called synonyms with columns id, word_id and synonym_id.
The synonyms table links words together that are synonyms. It links for example a bike and cycle together. But also bike to cycle etc.
I did manage to build this query in my phpstorm editor and it works:
select * from words
where id in (
select synonym_id from synonyms
where word_id in (select id from words where name = 'bike')
)
or id in (
select word_id from synonyms
where synonym_id in (select id from words where name = 'bike')
)
It returns a result set containing cycle, tandem, velocipede etc.
I did create a "word" eloquent model that has these methods:
/**
* Synonyms for this word
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function synonyms() {
return $this->belongsToMany(Word::class, 'synonyms', 'synonym_id', 'word_id');
}
/**
* Words that have this word as their synonym
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function isSynonymFor() {
return $this->belongsToMany(Word::class, 'synonyms', 'word_id', 'synonym_id');
}
And now I am trying to rebuild that query in eloquent like this:
$word = 'bike'; //Just for debugging purposes I hardcoded it.
$query = Word::whereHas('isSynonymFor', function(Builder $query) use($word) {
$query->where('name', '=', $word);
})->orWhereHas('synonyms', function(Builder $query) use($word) {
$query->where('name', '=', $word);
})
return $query->get();
This does not work like I want it too. It just returns a collection with "bike" in it and not the rest.
How can I fix it?
If you only want to reproduce that exact query (no eloquent relationships used), you should be able to do it just fine with whereIn(column, Closure) for the subqueries.
$query = DB::table('words')
->whereIn('id', function ($sub) {
$sub->select('synonym_id')
->from('synonyms')
->whereIn('word_id', function ($sub2) {
$sub2->select('id')
->from('words')
->where('name', 'bike');
});
})
->orWhereIn('id', function ($sub) {
$sub->select('word_id')
->from('synonyms')
->whereIn('synonym_id', function ($sub2) {
$sub2->select('id')
->from('words')
->where('name', 'bike');
});
})
// ->toSql();
->get();

Need to convert a query into Eloquent Model laravel

I have a query of MySQL but I need to convert it into an eloquent model laravel 8. The query is given below,
$query = "SELECT group_id FROM `chat_histories` join chat_group on chat_group.id = chat_histories.group_id where chat_group.is_group = 1 and chat_histories.created_at BETWEEN '$startDate' and '$endDate' and chat_histories.deleted_at is null group by group_id";
$query = "select count(group_id) as total_chat_thread from ($query) total_chat";
DB::select($query);
So far i have done this,
ChatHistory::leftJoin('chat_group', 'chat_group.id', '=', 'chat_histories.group_id')
->selectRaw('count(*) as totals')
->where('chat_group.is_group', 1)
->whereBetween('chat_histories.created_at', [$startDate, $endDate])
->groupBy('chat_histories.group_id')
->count('totals');
But this returns a list, but I need that count of the list. That means it's showing 22 rows, I need that 22 as return.
My Model ChatHistory relation with ChatGroup
public function chatGroup() {
return $this->belongsTo(ChatGroup::class, 'group_id', 'id');
}
My Model ChatGroup relation with ChatHistory
public function chatHistory() {
return $this->hasMany(ChatHistory::class,'group_id','id');
}
Please help to convert it into an eloquent model query
Thanks in advance.
If you have the model Group with a relation history hasMany. it should be like this.
$groupCount = ChatGroup::whereHas('chatHistory', function ($historyQB) use($startDate,$endDate) {
$historyQB->whereBetween('created_at', [$startDate, $endDate])
->whereNull('deleted_at');
})->count();
You dont need the whereNull, if the model ChatHistory has softDelete enabled.
Maybe you should consider using Models, it would be much easier/cleaner
Something like that should work
DB::table('chat_histories')->select('group_id')->join('chat_group', 'chat_group.id', 'chat_histories.group_id')->where('chat_groups.is_group', 1)->whereBetween('chat_histories.created_at', $startDate, $endDate)->whereNull('chat_histories.deleted_at')->groupBy('group_id')->count();

Select SUM from subquery while using whereHas in Laravel

I have 2 tables, customers and customer_invoices, and I want to get all the customers with a condition on their invoices, and select specific columns (customers.id, customers.last_name, and the sum of the total_price of the invoices for each customer), I have this query :
$result = Customer::whereHas('customerInvoices', function(Builder $q) {
$q->where('customer_invoices.status', 1);
})->select([
'customers.id',
'customers.last_name',
\DB::raw('SUM(customer_invoices.total_price) as sum')
])->get();
customerInvoices is the relation :
public function customerInvoices() {
return $this->hasMany(CustomerInvoice::class);
}
I want to use subqueries instead of joins, so here I can't select this \DB::raw('SUM(customer_invoices.total_price) as sum'), or else I get this error of course :
"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'customer_invoices.total_price' in 'field list' (SQL: select `customers`.`id`, `customers`.`last_name`, SUM(customer_invoices.total_price) as sum from `customers` where exists (select * from `customer_invoices` where `customers`.`id` = `customer_invoices`.`customer_id` and `customer_invoices`.`status` = 1))"
How can I achieve this without using joins ?
You can use withCount() to get sum from related model as
$result = Customer::select([
'customers.id',
'customers.last_name'
])->withCount([
'customerInvoices as invoice_sum' => function($query) {
$query->select(DB::raw('SUM(total_price)'));
}
])->whereHas('customerInvoices', function(Builder $q) {
$q->where('customer_invoices.status', 1);
})->get();
Another approach to get sum, you can define a hasOne() relation in your Customer model like
public function invoice_sum()
{
return $this->hasOne(CustomerInvoice::class)
->select('customer_id',
DB::raw('sum(total_price)')
)->groupBy('customer_id');
}
And in query builder
$result = Customer::select([
'customers.id',
'customers.last_name',
])->with('invoice_sum')
->whereHas('customerInvoices', function(Builder $q) {
$q->where('customer_invoices.status', 1);
})->get();
As per Eloquent : withCount() overrides the $columns on get() issue first put select() mehtod and then use with() function

Where not Exists en Laravel

Could anybody tell me what error I might have in my laravel query, basically what I want is to list the records of a table whose id is not related in another table. I did it in Mysql with this query: SELECT * FROM item WHERE NOT EXISTS (SELECT null FROM qualifications WHERE grades.item_id = item.id AND qualifications.user_id = 2);
but now I need to do this same query in laravel, I tried it this way:
codigo
and what I get is this syntax error that I do not know how to solve anymore:
error
I am very grateful to anyone who can tell me what I am doing wrong, or in what form I make that query in Laravel.
You can also rewrite your query as left join like
SELECT i.*
FROM item i
LEFT JOIN qualifications q ON q.item_id = i.id AND q.user_id = 2
WHERE q.item_id IS NULL
In query builder you can write it as
DB::table('item as i')
->select('i.*')
->leftJoin('qualifications as q', function ($join) use($user_id) {
$join->on('q.item_id', '=', 'i.id')
->on('q.user_id', '=', $user_id);
})
->whereNull('q.item_id')
->get();
Another approach which i suggest you to go with, is setup your relations and models and do it with eloquent way
class Item extends Model
{
public function qualifications()
{
return $this->hasMany(\App\Models\Qualification::class, 'item_id');
}
}
class Qualification extends Model
{
public function qualifications()
{
return $this->belongsTo(Item::class, 'item_id');
}
}
And then you can use Querying Relationship Absence
Item::whereDoesntHave('qualifications', function ($query) use($user_id) {
$query->where('user_id', '=', $user_id);
})->get();

Laravel Eloquent: Many-to-Many Select items without children (using pivot)

Pretty standard setup:
table "Posts",
table "Categories"
pivot "posts_categories"
/************** CATEGORY MODEL *********/
class Category extends Eloquent
{
/** standard code**/
public function posts()
{
return $this->belongsToMany('Post','posts_categories');
}
}
/************* POSTS MODEL ************/
class Post extends Eloquent
{
/** the usual **/
public function categories()
{
return $this->belongsToMany('Category', 'posts_categories');
}
pivot table with proper foreign keys setup.
I cannot seem to figure how to get ALL POSTS without any categories (or for that matter get categories without any posts, like empty categories)
I would like to do this in eloquent, but in sql it'd be something like:
SELECT *,
(SELECT COUNT(id) cnt
FROM posts_categories pc
WHERE pc.post_id = p.id) AS cnt
FROM posts p
HAVING cnt = 0;
You can use this to get all Posts that have no Category:
$posts = Post::has('categories', '=', 0)->get();