Laravel ORM query where with two columns and differents tables - laravel

I'm new in Laravel and maybe could be silly
1.- Query with two tables and using two columns in each table
class Post extends Model {
public function Comment()
{
return $this->hasMany('App\Comment');
}
}
Figure out the Post model has the column type. I want to consult where type = 1 and title = foo(comment model).The below example only has the title.
$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first();
2.- My second question, Is there a way to run the orm queries without running or render the application. I mean like sqlplus or mysql terminal.

Q1: I want to consult where type = 1 and title = foo(comment model).
A1: Constraining Eager Loads
// From the docs
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
// So in your case -
$comments = App\Comment::with(['posts' => function ($query) {
$query->where('type', '=', 1); // Constraints on the Post model
})->where('title', '=', 'foo')->first(); // Constraints on the Comment model
Q2: Is there a way to run the orm queries without running or render the application.
A2: - Use the Artisan Console
Read up on using the php artisan tinker with the link to the docs above.

Answering with your question
// Answer 1
Post::with('comments')->where([
['type', 1],
['comments.title', '=', 'foo']
])->get();
// Answer 2
// you can use tinker: https://laravel.com/docs/7.x/artisan#tinker

Related

Laravel: How to query a Model Relationship only if it exists

I have a model Survey with a column installer_id which is related to hasOne another model Installation which is related to hasMany another model Assignment.
I want to write a query to fetch all Survey where the installer_id is not null, and where IF an Assignment exists check all the assignments if any status is != 2 ie status = 0 or 1 return the survey.
I tried this query but it does not capture the "if an assignment exists then check the status" part
$surveys = Survey::whereNotNull('installer_id')
->orWhereHas('installation',function ($query) {
return $query->whereHas('assignments',function ($q){
return $q->where('status','!=', 2 );
});
})->get();
I also tried to define a hasManyThrough relationship in the model.
public function assignments()
{
return $this->hasManyThrough(Assignment::class,Installation::class);
}
and then using this query
$schedulables = Survey::whereNotNull('installer_id')
->orWherehas('assignments',function ($query){
return $query->where('assignments.status','!=', 2 );
})->get()
Please any suggestions and help would be appreciated
I think you had the correct approach, however whereNotNull is not necessary if you're already going to check with whereHas, so this way is sufficient I think:
$surveys = Survey::whereHas('installation',function ($query) {
return $query->whereHas('assignments',function ($q){
return $q->where('status','!=', 2 );
});
})->get();
and I think you're missing the ->get(); in your code, thats why you were not getting the results
Original answer
What i needed was the whereDoesntHave method.
$surveys = Survey::whereNotNull('installer_id')
->whereDoesntHave('installation.assignments', fn ($query) => $query->where('status', 2))
->get();

How to use where by second table Laravel?

I have the following query:
$objects = Object::with("prototypes");
As you can see I do request to model Object and join it with prototypes.
The prototypes table has structure:
prototype_id
name
How to make where in above query like as:
$objects = Object::with("prototypes")->where("prototype_id", 3);
Object model:
public function prototypes()
{
return $this->belongsToMany('App\Prototype', 'object_prototype', 'object_id');
}
Prototype model:
public function objects(){
return $this->belongsToMany("App\Object", "object_prototype", "prototype_id", "object_id");
}
If the relationship is correctly set in your Eloquent models, you can use the WhereHas function to query relationship existence.
$objects = Object::with('prototypes')
->whereHas('prototypes', function ($query) {
$query->where('prototype_id', 3);
})
->get();
Just to add on #Jerodev answer.
If you need even more power, you may use the whereHas and
orWhereHas methods to put "where" conditions on your has queries.
These methods allow you to add customized constraints to a
relationship constraint, such as checking the content of a comment:
// Retrieve all posts with at least one comment containing words like foo%
$posts = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
You can read more about Eloquent Relationships
And in your case you can also construct a your query like.
Object::whereHas('prototypes', function ($query)){
$query->where('prototype_id', 3);
})->get();

How to query a table using result of many-to-many relation with Eloquent ORM?

here is link to my database schema:
How can I get all topics from the blogs to which the user is subscribed using his id? I use Eloquent ORM.
I have added the following lines to my User model:
public function blogs()
{
return $this->belongsToMany('Blog', 'blog_subscriptions');
}
And then requested in the controller
User::find(1)->blogs; // User id is hardcoded
With that I got all blogs to which the user is subscribed.
And now I am stuck on how to get the topics of those blogs.
Assuming relations:
// User
belongsToMany('Blog', 'user_subscriptions')
// Blog
belongsToMany('User', 'user_subscriptions')
hasMany('Topic')
// Topic
belongsTo('Blog')
1 My way, that will work with any relation, no matter how deeply nested:
User::with(['blogs.topics' => function ($q) use (&$topics) {
$topics = $q->get()->unique();
}])->find($userId);
2 Eloquent standard methods:
$topics = Topic::whereHas('blog', function ($q) use ($userId) {
$q->whereHas('users', function ($q) use ($userId) {
$q->where('users.id', $userId);
});
})->get();
// or
$user = User::find($userId);
foreach ($user->blogs as $blog)
{
$blog->topics; // collection of topics for every single blog
}
3 Joins:
$topics = Topic::join('blogs', 'topics.blog_id', '=', 'blogs.id')
->join('user_subscriptions as us', function ($j) use ($userId) {
$j->on('us.blog_id', '=', 'blogs.id')
->where('us.user_id', '=', $userId);
})->get(['topics.*']);
Mind that last solution will rely on your pivot data consistency. That said, if you can't be sure, that there are no redundant entries in user_subscriptions (eg. blog or user has been deleted but the pivot entry remains), then you need to further join users as well.
I am new to laravel and I don't have the possibility of test this, but I had a similar need and solved it with something like this:
DB::Query('topics')->join('blogs', 'blogs.id', '=', 'topics.blog_id')
->join('blog_subscriptions', 'blogs.id', '=', 'blog_subscriptions.blog_id')
->select('name.id','table.email')
->where('blog_subscriptions.user_id', '=', $user_id);

Laravel eloquent: get data with model wherePivot equal to custom field

I have an eloquent object Performer that has Albums and Albums have Images
Here is setup:
Model Performer->albums():
public function albums()
{
return $this->belongsToMany('Album','performer_albums','performer_id','album_id');
}
Model Album->images()
public function images()
{
return $this->belongsToMany('Image','album_images','album_id','image_id')->withPivot(['type','size']);
}
I have performer object stored as such:
$performer = Performer::where...->first();
Now I need to get Performer's Albums with images where size is 'large'
So to avoid nesting queries, can I use with()?
I tried
$performer->albums()
->with('images')
->wherePivot('size','large')
->get();
But laravel tells me it's trying to use wherePivot for Performer-Album relationship (M-2-M)
PS. I am also aware that I can do this,
$performer = Performer::with('albums')
->with('albums.images')
->.....-conditions for additional fields in album_images....
->get();
but question remains the same.
You need eager load constraints:
$performer->albums()
->with(['images' => function ($q) {
$q->wherePivot('size','large');
}])
->get();
And btw, no, you can't do this:
Performer::with('albums')
->with('albums.images')
->.....-conditions for additional fields in album_images....
->get();
instead you could do:
Performer::with(['albums.images' => function ($q) {
$q-> .....-conditions for additional fields in album_images....
}])->get();

laravel search many to many Relashionship

I am testing eloquent for the first time and I want to see if it suit my application.
I have Product table:
id, name
and model:
class Produit extends Eloquent {
public function eavs()
{
return $this->belongsToMany('Eav')
->withPivot('value_int', 'value_varchar', 'value_date');
}
}
and eav table:
id, name, code, field_type
and pivot table:
product_id, eav_id, value_int, value_varchar, value_date
class Eav extends Eloquent {
public function produitTypes()
{
return $this->belongsToMany(
'ProduitType'
->withPivot('cs_attributs_produits_types_required');
}
All this is working.
But I want to search in that relashionship:
e.g: all product that have eav_id=3 and value_int=3
I have tested this:
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
}))->get();
But I get all the product, and eav data only for these who have id=3 and value_int=3.
I want to get only the product that match this search...
Thank you
I know the question is very old. But added the answer that works in the latest versions of Laravel.
In Laravel 6.x+ versions you can use whereHas method.
So your query will look like this:
Produit::whereHas('eavs', function (Builder $query) {
// Query the pivot table
$query->where('eav_id', 3);
})->get()
My suggestion and something I like to follow is to start with what you know. In this case, we know the eav_id, so let's go from there.
$produits = Eav::find(3)->produits()->where('value_int', '3')->get();
Eager loading in this case isn't going to save you any performance because we are cutting down the 1+n query problem as described in the documentation because we are starting off with using find(). It's also going to be a lot easier to read and understand.
Using query builder for checking multiple eavs
$produits = DB::table('produits')
->join('eav_produit', 'eav_produit.produit_id', '=', 'produits.id')
->join('eavs', 'eavs.id', '=', 'eav_produit.eav_id')
->where(function($query)
{
$query->where('eav_produit.value_int','=','3');
$query->where('eavs.id', '=', '3');
})
->orWhere(function($query)
{
$query->where('eav_produit.value_int','=','1');
$query->where('eavs.id', '=', '1');
})
->select('produits.*')
->get();
Making it work with what you already have...
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
$query->orWhere('id', '1')->where('value_int', '1');
}))->get();
foreach($produits as $produit)
{
if(!produit->eavs)
continue;
// Do stuff
}
From http://four.laravel.com/docs/eloquent:
When accessing the records for a model, you may wish to limit your results based on the existence of a relationship. For example, you wish to pull all blog posts that have at least one comment. To do so, you may use the has method
$posts = Post::has('comments')->get();
Using the "has()" method should give you an array with only products that have EAV that match your criteria.
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
}))->has('eavs')->get();

Resources