whereHas is not working on NULL value - api

in laravel 5.5 whereHas() is not working on where value is NULL. my relationship with other model is one to many and and i want to pick the values from the model where value is equal to NULL . But instead of returning the specific values its returning all the value in result
plans = Plan::with('objectives')->with('objectives.keyResults')
->whereHas('objectives', function($query) {
$query->whereNull('entity_id');
$query->whereNull('quarter_id');
})->where('companyKey', Auth::user()->companyKey)->get();

You have to specify the constraint twice:
$plans = Plan::with(['objectives' => function($query) {
$query->whereNull('entity_id');
$query->whereNull('quarter_id');
}, 'objectives.keyResults'])
->whereHas('objectives', function($query) {
$query->whereNull('entity_id');
$query->whereNull('quarter_id');
})->where('companyKey', Auth::user()->companyKey)
->get();

No double constraints are needed, simplify it to:
$plans = Plan::whereHas('objectives', function($query) {
$query->whereNull('entity_id');
$query->whereNull('quarter_id');
})->with(['objectives'])
->where('companyKey', Auth::user()->companyKey)
->get();

Related

Can Laravel automatically switch between column = ? and column IS NULL depending on value?

When building a complex SQL query for Laravel, using ? as placeholders for parameters is great. However when the value is null, the SQL syntax needs to be changed from = ? to IS NULL. Plus, since the number of parameters is one less, I need to pass a different array.
To get it to work, I have written it like this, but there must be a better way:
if ($cohortId === null) {
// sql should be: column IS NULL
$sqlCohortString = "IS NULL";
$params = [
Carbon::today()->subDays(90),
// no cohort id here
];
} else {
// sql should be: column = ?
$sqlCohortString = "= ?";
$params = [
Carbon::today()->subDays(90),
$cohortId
];
}
$query = "SELECT items.`name`,
snapshots.`value`,
snapshots.`taken_at`,
FROM snapshots
INNER JOIN (
SELECT MAX(id) AS id, item_id
FROM snapshots
WHERE `taken_at` > ?
AND snapshots.`cohort_id` $sqlCohortString
GROUP BY item_id
) latest
ON latest.`id` = snapshots.`id`
INNER JOIN items
ON items.`id` = snapshots.`item_id`
ORDER by media_items.`slug` ASC
";
$chartData = DB::select($query, $params);
My question is: does Laravel have a way to detect null values and replace ? more intelligently?
PS: The SQL is for a chart, so I need the single highest snapshot value for each item.
You can use ->when to create a conditional where clause:
$data = DB::table('table')
->when($cohortId === null, function ($query) {
return $query->whereNull('cohort_id');
}, function ($query) use ($cohortId) {
// the "use" keyword provides access to "outer" variables
return $query->where('cohort_id', '=', $cohortId);
})
->where('taken_at', '>', $someDate)
->toSql();

Laravel QueryBuilder condition

In Laravel, I want to build a query like following.
There is a status column, value should be 0 or 1.
And there is another column, device_ids with array.
Now,in query, I want to apply different logic on device_ids, when status is 0 and status is 1.
Can someone suggest me best possible way.
$builder->where('status','0')->whereJsonDoesntContain('device_ids', $imei_id->id)
$builder->where('status','1')->whereJsonContains('device_ids', $imei_id->id)
How can I combine both ?
$all_applications = $builder->where('status', $model->status)
->when($status, function ($query) {
Log::error("One");
return $query->whereJsonContains('device_ids', 107); },
function($query) {
Log::error("Zero"); return $query
->whereJsonDoesntContain('device_ids', 107); });
If I use $model->status , it gives me error like , "Undefined variable: model"
You have to use when.
$result = YourModel::where('status', $status)
->when($status, function ($query) {
return $query->whereJsonContains('device_ids', $imei_id->id);
}, function ($query) {
return $query->whereJsonDoesntContain('device_ids', $imei_id->id);
});

How count by the first letters in Laravel Query Builder?

I want to make a count by the first letters... I have this column
I would like to count each OE rows and each GICS rows
I'm working with this query
$data4 = DB::table('incidencias')
->select(DB::raw('grupo_asig as grupo_asig'), DB::raw('count(*) as number'))
->whereNotIn('grupo_asig', [''])
->groupBy('grupo_asig')
->orderBy('number', 'desc')
->get();
Use CASE WHEN and count the field like OE and ASIG
$data4 = DB::table('incidencias')
->select(DB::raw("(CASE WHEN grupo_asig LIKE 'OE%' THEN 'OE'
WHEN grupo_asig LIKE 'GICS%' THEN 'GICS'
END) AS grupo_asig_type"),
DB::raw('COUNT(*) as number'))
->whereNotIn('grupo_asig', [''])
->groupBy('grupo_asig_type')
->orderBy('number', 'desc')
->get();
You should try to use the [LIKE][1] function then and add it to your query:
->where('grupo_asig', 'like', 'OE%')
->where('grupo_asig', 'like', 'GICS%')
Edit:
I tried a lot around and came to this solution and made a SQL fiddle: http://sqlfiddle.com/#!9/06a39b/8
Does it help you?
You could use Collections. No real need to change your query much.
$data4 = DB::table('incidencias')
->select('grupo_asig')
->selectRaw('count(*) as number'))
->whereNotIn('grupo_asig', [''])
->groupBy('grupo_asig')
// ->orderBy('number', 'desc') Unless you use this array somewhere, it's not needed.
->get();
use Illuminate\Support\Str;
...
// php >= 7.4.0
$oe_count = $data4->filter(fn($data) => Str::startsWith($data->grupo, 'OE '))->count();
$gigs_count = $data4->filter(fn($data) => Str::startsWith($data->grupo, 'GIGS '))->count();
// php < 7.4.0
$oe_count = $data4->filter(function ($data) {
return Str::startsWith($data->grupo, 'OE ');
})->count();
$gigs_count = $data4->filter(function ($data) {
return Str::startsWith($data->grupo, 'GIGS ');
})->count();
Starting with Laravel 6, you can also use cursor() instead of get() in your query to return a LazyCollection. It's faster for this scenario.
I would suggest using a query for that:
refer to this answer
SELECT
LEFT(grupo_asig, 1) AS first_letter,
COUNT(*) AS total
FROM incidencias
GROUP BY first_letter

Select specific columns of table and relation in laravel

Lets consider I have a Model User and another Model Employee
Now I want to pluck only some fields of Employee model such as salary, id, emp_id along with some columns of User model such as name,id.
$employee = Employee::with('user:id,name')
->where('department', $request->department)
->get(['id', 'emp_id', 'salary']);
When I execute this it will return id,emp_id,salary data but for user:name,id it will return null
How can I also specify user:id,name in get() ?
You can either load the full model or only some fields of it. To only load some fields, use select(). It also works within the relationship eager loading query:
$employees = Employee::with(['user' => function ($query) {
$query->select(['id', 'employee_id', 'name']);
}])
->where('department', $request->department)
->select(['id', 'emp_id', 'salary'])
->get();
use select() method from Query bulider:
$employee = Employee::with('user') // or users <---
->select(['id', 'emp_id', 'salary', 'users.id AS user_id', 'users.name AS username'])
->where('department', $request->department)
->get();

How to select items by providing where clause in pivot

This is my code looks like right now :
$result = Category::with(array(
"getProducts",
"getProducts.getBrand",
"getProducts.getImages",
"getProducts.getDetail",
"getProducts.getTax",
"getProducts.getDiscount",
"getProducts.getAttributes" => function($query) use($_temp){
if($_temp != null){
$query->where_in('attributes.id',$_temp);
}
},
"getSlideshow",
"getSlideshow.getItems",
"getAttributeListing",
"getAttributeListing.getAttributes",
"getAttributeListing.getAttributes.productSpecific"
))
->where('id','=', $category_id)
->first();
Yet, It only filters the getProducts.getAttributes items not the 'getProducts' itself. Is there a way that I can get the Products by attributes?
Note: I am using Laravel 3