Three main tables:
products
advertisers
locations
Two pivot tables:
advertisers_locations
products_locations
Relationships:
A product belongs to an advertiser and an advertiser has many locations (Locations it can ship products to)
A product can also have it own set of locations that override the advertiser locations (Some products have delivery restrictions)
What I need to do is:
Select all products
Check if products_locations table for product ID and join it.
If it does not exist then join the advertisers locations table
Is this possible to do in one query and using eloquent? Here's my code - struggling with the conditional:
public function scopeWhereShippableToLocation($query)
{
$location_id = session('location_id');
$query->where(function ($q) use ($location_id) {
$q->join('products_locations', 'products_locations.product_id', '=', 'products.id')
->where('products_locations.location_id', '=', $location_id);
});
$query->orWhere(function ($q) use ($location_id) {
$q->join('advertisers_locations', 'advertisers_locations.advertiser_id', '=', 'products.advertiser_id')
->where('advertisers_locations.location_id', '=', $location_id);
});
//dd($q->toSql());
return $query;
}
This is currently producing a MySQL error:
Column not found: 1054 Unknown column 'products_locations.location_id' in 'where clause' (SQL: select `products`.*,
I think I have a solution for you using eloquent, rather than the query builder. You need to check to see if the relationship exists, if not you need another query. This can be done using the following:
public function scopeWhereShippableToLocation($query)
{
$location_id = session('location_id');
// WhereHas check to see if a relationship exists, IE: The pivot table
// orWhereHas will be checked if the first where does not exist
$query->whereHas('products_locations', function ($q) use ($location_id) {
$q->where('location_id', $location_id);
})->orWhereHas('advertisers_locations', function ($q) use ($location_id) {
$q->where('location_id', $location_id);
});
return $query;
}
This should work providing that your Products, Advertisers and Locations relationship methods are set up.
Related
for example I have 3 tables and that tables has a relation,
Table A
id
name
Table B
id
tableId_A
tableId_C
Table C
id
name
i'm using table C but i want to search items by request name that have the same name as in table A using query eloquent
and this is the query, i'm using a laravel
$this->model->query()
->withWhereHas('tableB', function($query) use ($names) {
$query->tableB->where('name', 'LIKE', "%{$names}%");})
how to fix it using eloquent where has used 3 tables relation?
I think your relation name should be tableA not tableB.
public function tableA()
{
return $this->belongsToMany(TableAModel::class, 'TableB', 'tableId_C', 'tableId_A')
->where('TableA.status', CoreStatusEnum::ACTIVE);
}
And your query goes like this..
$this->model->query()
->withWhereHas('tableA', function($query) use ($names) {
$query->where('name', 'LIKE', "%{$names}%");
})
->get();
I am trying to make a query using Laravel eloquent but at the moment I have not had good results.
My query is about the scope of relationships in Laravel. We have two tables:
table 1 : orders
table 2 : products in orders (depends on table 1)
We have a relationship in the model.
public function products()
{
return $this->hasMany(OrderProduct::class);
}
OrderProduct (detail of products in orders) has the following fields:
id
order_id
product_id
qty
line_total
What we are trying to achieve is a query that returns the sum of line_total when the product_id is 139.
We tried the following options without success in the controller:
$orderspaid = Order::with('products')
->where('customer_id', '=', Auth::id())
->where('status', '=', 'completed')
->withSum ('products','line_total')
->where('product_id', '=', '139')
->get();
Error: Column not found: 1054 Unknown column 'product_id'
$orderspaid = Order::withCount(['products as orderproducts' => function($query) {
$query->where('orderproducts.product_id', '=', 139)
->select(DB::raw('sum(line_total)'));
}])->get();
But with no success.
My main question is, it is possible to use sum(line_total) or withSum('products','line_total') to directly sum the amount of money that a particular product_id have?.
Additional Info: Tinker information displaying the relationship between orders and orderproducts.
You can try this one. I don't have those tables ready to test so I could be wrong
So basicly, the method being tried is that products with wanted id will be preloaded, in this case, it's 139. When withSum is called on products table, it will use eagerly products that have been specified beforehand.
$product_id = 139;
$orderspaid = Order::with(['products' => function ($query) use ($product_id) {
$query->where(`products.id`, $product_id);
}])
->where('customer_id', '=', Auth::id())
->where('status', '=', 'completed')
->withSum('products', 'line_total')
->get();
dd($orderspaid);
Tell me if that works for you.
I have the following query:
Ratings::join('users', 'movieratings.rated_by', '=', 'users.usr_id')
->where('rated_on', $movieId)
->orderBy('rated_at', 'desc')
->select('comment', 'rating', 'rated_as', 'rated_at', 'username')
->paginate(20);
This will get all the feedback ratings for a specific movie.
But I have another table which contains the total good and bad ratings for a specific movie movie, the only problem is that I cant get it to work to query that table as well at the same time.
If I do another query I would simply write: Movie::where('movie_id', $movieId)->select('total_good_ratings', 'total_bad_ratings')->get(); this would output eg "22, 15" but is it possible to only fetch two columns from a specific row then do a inner join between two tables and paginate the result?
thanks
You can do a leftJoin with the table that contains the good and bad ratings, where the join condition will be the id of the movie.
Ratings::join('users', 'movieratings.rated_by', '=', 'users.usr_id')
->leftJoin('movie', 'movie.id', '=', 'movieratings.rated_on')
->where('rated_on', $movieId)
->orderBy('rated_at', 'desc')
->select('comment', 'rating', 'rated_as', 'rated_at', 'username', 'total_good_ratings', 'total_bad_ratings')
->paginate(20);
I think you can try this:
Ratings::leftJoin('users', 'users.usr_id', '=', 'movieratings.rated_by')
->leftJoin('movie', 'movie.id', '=', 'movieratings.rated_on')
->where('movieratings.rated_on', $movieId)
->orderBy('movie.rated_at', 'desc')
->select('movieratings.comment', 'movieratings.rating', 'movieratings.rated_as', 'movie.rated_at', 'users.username', 'movieratings.total_good_ratings', 'movieratings.total_bad_ratings')
->paginate(20);
Hope this help for you !!!
In case this may be of help:
Assuming:
class Rating extends Model {
public users() {
$this->belongsTo(User::class, 'usr_id');
}
public movie() {
$this->belongsTo(Movie::class, 'rated_on'); //Name looks odd, it should be movie_id if you are following standard conventions
}
}
Then you can lazy/eaher load them:
$ratings = Ratings::with([ "movie" => function ($query) {
$q->select('total_good_ratings', 'total_bad_ratings');
}])->where('rated_on', $movieId)
->orderBy('rated_at', 'desc')
->select('comment', 'rating', 'rated_as', 'rated_at', 'username',"rated_on")
->paginate(20);
You can get the movie info via $ratings[X]->movie->total_good_ratings (in a loop that would be $rating->movie->total_good_ratings
A bit of critique though:
total_good_ratings looks like it's a derived attribute so it should not have been stored in the first place. It's appears to be a count of the good ratings.
You should use the standard conventions when naming columns and tables e.g. a foreign key is usually called <foreign table name in singular>_<foreign field name> example user_id or movie_id .
I'm quite new to Laravel and I'm now facing this issue while trying to create a query:
I have the following Morphable classes:
\App\User
class User {
public function userable()
{
return $this->morphTo();
}
}
\App\Distributor
class Distributor {
public function user()
{
return $this->morphOne('App\User', 'userable');
}
}
user table has the fields: name, email, status, userable_type and userable_id.
distributor table has the fields: store_code and location_id.
By using Eloquent, i need to start the query from Distributor model and select only the following fields: 'name, email, store_code'.
I'm trying the following, but laravel says user.name doesn't exists :(
$queryBuilder = \App\Distributor::has('user');
$queryBuilder->select(['user.name']);
$queryBuilder->get();
QueryException in Connection.php line 651:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user.name' in 'field list' (SQL: select user.name from distributor where (select count(*) from user where user.userable_id = distributor.id and user.userable_type = App\Distributor and user.deleted_at is null) >= 1)
I was able to achieve my goal forcing the join relationship, but this seems wrong, I think Eloquent is able to find the relation by itself as the Morph relationship is specified in the Model.
Just for record, this works good:
$queryBuilder = \App\Distributor::has('user');
$queryBuilder->join('user', function($join) {
$join->on('userable_id', '=', 'distributor.id')
->where('userable_type', '=', \App\Distributor::class);
});
$queryBuilder->select(['user.name']);
$queryBuilder->get();
Also, since its a one-to-one like relationship, sometimes I'll need to order the results using one of the users columns
But I need another way to do it without forcing the join, something clean as the first example.
read about with() function in the docs
$queryBuilder->select('id','store_code');
$queryBuilder = \App\Distributor::with(['user'=>function($query){
$query->select('id','name','email')
}]);
$queryBuilder->has('user');
$queryBuilder->get();
Hi I am building an application and I have a table for example projects and then settings. However they do not have a foreign key with each other and i have other tables such as tasks, clients etc. And these have settings which I am planning to save in the settings table.
The settings table has a column of type, which i will fill with the related model name e.g. project. Anyway when i am fetching a project I also want to fetch a the settings where the type = project. So I've tried to do a table join instead however this has thrown the following error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'project' in 'on clause' (SQL: select * from `projects` inner join `settings` on `type` = `project`)
The code I've used is as follows:
return \Project::()->join('settings', 'type', '=', 'project')->get();
I see what the problem is, its looking for a column called project however there isn't one. I suppose what i want to do is use eloquent and a query function to join the table and then query the settings table where type = project. does anyone know how i can do this?
update from burak answer
I've tried to put this in my model as so so
settings.php
public function sprint() {
return \Setting::where('type', '=', 'sprint')->get();
}
and sprint.php
public function settings() {
return \Setting::where('type', '=', 'sprint')->get();
}
however I get this error Call to undefined method
Illuminate\Database\Eloquent\Collection::addEagerConstraints() and I've called it using this method:
return Sprint::with(['settings'])->get();
what have i done wrong here?
Because you are not referencing the table names and you are comparing columns. Instead, what you need is a where statement within your join condition to compare with a value.
return DB::table('projects')
->join('settings', function ($join) {
$join->where('settings.type', '=', 'project');
})->get();
But you should better get settings and projects one by one as all identical settings columns will be added to your projects rows which is not good.
$data = [];
$data['projects'] = Project::all();
$data['settings'] = Settings::where('type', '=', 'project')->first();
return $data;
Update:
Within your Sprint model
public function scopeWithType()
{
return static::join('settings', function ($join) {
$join->where('settings.type', '=', 'sprint');
});
}
Then within the controller
Sprint::withType()->get();
I have not tried but I think this is what you want. This is how we do subqueries or query joins with where clause.
return \Project::join('settings', function($q) {
$q->where('type', '=', 'project');
})->get();
your code looks for records matching project field in the table settings and type field in the project table, which is not the case.