WhereNotIn not working in eager loading laravel? - laravel

I Am using in Laravel 8 app next lines of codes, the problem is it is not filtering anything.
When I am using whereIn instead my app returns items as expected but when I add whereNotIn something goes wrong and not returning items opposite items to whereIn but all items.
$callback = function ($query) {
$query->whereHas('documents', function($query) {
$query->whereNotIn('document_type_id', $this->negative_documents);
});
};
$companies = $companies->whereHas('people', $callback)->with('people', $callback);
Any ideas?

Related

Laravel, eloquent, query: problem with retriving right data from DB

I'm trying to get the right data from the database, I'm retriving a model with a media relation via eloquent, but I want to return a photo that contains the 'main' tag stored in JSON, if this tag is missing, then I would like to return the first photo assigned to this model.
how i assign tags to media
I had 3 ideas:
Use orWhere() method, but i want more likely 'xor' than 'or'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main')->orWhere();
}]);
return $models->paginate(self::PER_PAGE);
Raw SQL, but i don't really know how to do this i tried something with JSON_EXTRACT and IF/ELSE statement, but it was to hard for me and it was a disaster
Last idea was to make 2 queries and just add media from second query if there is no tag 'main'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}]);
$models_all_media = Model:: with(['media']);
return $models->paginate(self::PER_PAGE);
but i tried something like
for($i=0; $i<count($models); $i++) {
$models->media = $models_all_media
}
but i can't do this without get() method, beacuse i don't know how to change this to LengthAwarePaginator class after using get()
try using whereHas https://laravel.com/docs/9.x/eloquent-relationships
Model::with('media')
->whereHas('media',fn($media)=>$media->whereJsonContains('custom_properties->tags', 'main'))
->paginate(self::PER_PAGE);
as per your comment you can use
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}])
->leftJoin('media', function ($join) {
$join->on('models.id', '=', 'media.model_id')
->whereNull('media.custom_properties->tags->main');
})
->groupBy('models.id')
->paginate(self::PER_PAGE);
return $models;

Laravel 5.4: Filter and meet all arguments from request

I need your help. Still learning a lot about Laravel and been searching the whole web for a solid answer to this question. I'm trying to get a collection of products that meet all the given request arguments. So:
?brand=adidas,nike&gender=women
Will get me all the Adidas & Nike shoes for Women.
I've got this so far:
$brandRequest = $request->brand;
$brandReqArray = explode(',', $brandRequest);
$genderRequest = $request->gender;
$genderReqArray = explode(',', $genderRequest);
$products = Product::with('brands', 'genders')
->whereHas('brands', function($query) use ($brandReqArray) {
$query->whereIn('slug', $brandReqArray);
})
->orWhereHas('genders', function($query) use ($genderReqArray) {
$query->whereIn('slug', $genderReqArray);
})->paginate(24);
I'm getting all the Adidas & Nike shoes and I'm getting all the women shoes. But if I'm trying both it shows nothing.
Here's my table structure: DB Table structure
Can someone point me in the right direction or maybe even has a solution for this?
Thanks! :)
you should consider using ->when in your laravel query to make conditional statement. , Please note that you cannot use inbuilt pagination in this way, it will not work appropriately, because pagination link is constructed without taking care of your parameters exist in the URL, I would advice you to make an ajax pagination.
try to execute this query and it should work without pagination.
$products = Product::when($request->has('brand'), function ($query)use($request) {
$brandRequest = $request->input('brand');
$brandReqArray = explode(',', $brandRequest);
$query->whereHas('brands', function($q) use ($brandReqArray) {
$q->whereIn('slug', $brandReqArray);
});
})->when($request->has('gender'), function ($query)use($request) {
$genderRequest = $request->input('gender');
$genderReqArray = explode(',', $genderRequest);
$query->whereHas('genders', function($q) use ($genderReqArray) {
$q->whereIn('slug', $genderReqArray);
});
})->get();
for pagination, please try this way, but I advice you to avoid constructing pagination from URL parameter for security concerns,
$products = Product::when($request->filled('brand'), function ($query)use($request) {
$brandRequest = $request->input('brand');
$brandReqArray = explode(',', $brandRequest);
$query->whereHas('brands', function($q) use ($brandReqArray) {
$q->whereIn('slug', $brandReqArray);
});
})->when($request->filled('gender'), function ($query)use($request) {
$genderRequest = $request->input('gender');
$genderReqArray = explode(',', $genderRequest);
$query->whereHas('genders', function($q) use ($genderReqArray) {
$q->whereIn('slug', $genderReqArray);
});
})->paginate(10);
$input = $request->only(['brands', 'gender']);
$products->appends($input);
come to my blog and write any Laravel help OR find existing solution which might be helpful for you,
https://www.techalyst.com/
for ajax pagination refer one of my old article.
https://www.techalyst.com/links/read/97/laravel-ajax-pagination-for-collection-query-builder-complex-sql-query-result

How to remove fields from Laravel JSON Api response

I have an API returning an object with one-to-one relation to another object. As the models behind the objects, do have timestamps, these are also delivered when asking API.
// Get all transactions
Route::get('transaction', function() {
return Transaction::with('Personone','Persontwo')->get();
});
How do I prevent Laravel from returning the timestamps of the objects in the API?
I googled, but only found some hints to middleware or response macros but found no example pointing me into the right direction. Maybe you can help me.
You can make attributes "hidden" so that they do not show up in json.
docs
class Transaction extends Model
{
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = ['timestamp'];
}
I'm not sure if I get the question correctly but if you want to select from eager loads there are two ways
first one is inline selecting
Route::get('transaction', function () {
return Transaction::with('Personone:id,foo,bar', 'Persontwo:id,foo,bar,foobar')->get();
});
second one is to pass a closure
Route::get('transaction', function () {
return Transaction::with([
'Personone' => function ($query) {
$query->select('id', 'foo', 'bar');
},
'Persontwo' => function ($query) {
$query->select('id', 'foo', 'bar', 'foobar');
}])->get();
});
Eager Loading Specific Columns You may not always need every column
from the relationships you are retrieving. For this reason, Eloquent
allows you to specify which columns of the relationship you would like
to retrieve:
$users = App\Book::with('author:id,name')->get();
Constraining Eager Loads Sometimes you may wish to eager load a
relationship, but also specify additional query constraints for the
eager loading query. Here's an example:
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%'); }])->get(); In this example, Eloquent will only eager load posts where the post's title
column contains the word first. Of course, you may call other query
builder methods to further customize the eager loading operation:
$users = App\User::with(['posts' => function ($query) {
$query->orderBy('created_at', 'desc'); }])->get();

Where clause in With() laravel doesn't work

Hello I have a little problem with eloquent in Laravel 5.
I have this function:
$lists = Model::with(array('relation_with_registered_in_model'=>function($query){
$query->where("name","cccc");
}))->get();
My poblem is that return always all results, ignoring where clause.
I tried to print my query (generated with function) and if I execute the query in my phpmyadmin it return correct filtered results.
What I'm wrong?
You could try with single qoute
$lists = Model::with(array('relation_with_registered_in_model'=>function($query){
$query->where('name','cccc');
}))->get();
I have resolved and Understand my error:
In this posts it is explained https://laracasts.com/discuss/channels/general-discussion/problem-with-the-eager-loading-of-laravel-eloquent-orm?page=1
// gets only models that have relation matching the closure constraint
// no eager loading of the relation!
Model::whereHas('relation', function ($q) { ...} );
// gets ALL models
// and eager loads the relation, but only rows matching the constraint
Model::with(['relation' => function ($q) { ...} ]);

Laravel Eloquent: Get current id from inner function

I know, we can do this in the controller:
User::with('post')->get();
It will get every user's post from the database, based on users.id.
But the problem is, I want to do this:
User::with(['post' => function($query) {
# Throw users.id here...
}])->get();
How to do that?
You should get the users first, and then load related posts with a separate query and merge them manually.
$users = User::get();
$posts = Post::whereIn('user_id', $users->pluck('id'))->get(); // Get your additional data in this query
$users->each(function ($user) use ($posts)
{
$user->posts = $posts->where('user_id', $user->id);
});
Note: I did not test the code above. It's just an example to show you how to accomplish what you are trying to do.

Resources