please ignore syntax errors
im working on a system with these tables
products : id , title
1 p1
custom_field : id , title
10 color
11 something all products have
custom_field_attach : custom_field_id , product_id
10 1
11 0
i want to get product custom fields
i can have this relation in Product model
function CustomFields(){
return $this->belongsToMany(CustomField::class , 'custom_field_attach');
}
and have this query
$product = Product::with('CustomFields')->get();
but the thing is some custom_fields are for all the products so in the custom_field_attach table
product_id is 0for those custom_fields
sine my relation is using product_id as foreign key i wont get those rows with product_id = 0 in the result
basically i want
custom_field_attach where product_id = product.id OR product_id = 0
to make thisng simpler i can have this relation in Product model
function CustomFieldAttach(){
return $this->hasMany(CustomFieldAttach::class);
}
no i want something like
$product = Product::with(['CustomFieldAttach' => function($CustomFieldAttach){
// where forieng key works product_id=product.id orWhere product_id =0
}])->get();
i know i can do this with query builder but i want to use relation if possible
please note someone else has written this code and im just adding some features to the system ... changing the db structure is not an option
Related
I have two models in my project
Product and Product attributes
The relationship between them is one to many, so i can get product with relative attributes. Now I need to get a list of products and also get common product attributes between selected products. As in ex:
Product
id
Product
1
Apple
2
Pear
3
Ananas
Product attributes
id
attribute
product_id
1
fruit
1
2
fruit
2
3
fruit
3
4
green
1
5
yellow
2
6
brown
3
Now when I'm extracting all 3 products, i want to get their common attributes, in this case the common attribute is "fruit". How can I do this with laravel eloquent?
As per your current schema (which doesn't look good) you can get common attributes as
$products = Product::take(3)->get();
From above products collect product ids
$productIds = $products->pluck('id');
And then query product_attributes matching previously collected $productIds, this query will involve aggregation to satisfy your condition for common attributes.
$attributes = DB::table('product_attributes')
->select(['name',DB::raw('count(distinct product_id) total_count')])
->whereIn('product_id', $productIds)
->groupBy('name')
->havingRaw('total_count = ?', [count($productIds)])
->get();
Above query will return common attributes by checking the result of count() expression with count of $productIds if they match and this means that every products has this attributed attached to it.
At first, as said above, add many-to-many relationships, one-to-many is not suitable for that case. Then I can propose such a variant with two queries:
// select here product ids you need
$products = Product::all(['id']);
//select common attributes
$attibuteBuilder = ProductAttribute::query();
foreach($products as $product){
$attibuteBuilder->whereHas('products', function (Builder $builder) use ($product) {
$builder->where('product_id', $product->id);
})
}
$atributes = $attibuteBuilder->get();
The second variant: get the collection of products with attributes and check the general/
I have product table with product name and foreign key column named as subcategory I want to get product based on subcategory id and product name using or condition in codeigniter query method I wrote query for that but it is retrieving two record but i need only one record
for example we have table:
productid product subcategory
1 A 1
2 A 3
3 B 3
$var="some value from form(1 or 3)";
case 1: if product='A' and subcategory($var)=1 or subcategory ($var)=3 then it should get record with productid=1
case2 :if product='A' and subcategory($var)=2 or subcategory ($var)=3 then it should get record for productid=2 because we are using or condition it should check 1 or 3
the query which I have used it is retrieving two records but I need only one record if subcategory =1 or 3
Query:
$this->db->where('product', 'A');
$where = '(subcategory="1" or subcategory = "3")';
$this->db->where($where);
$this->db->get('product');
$query = $gsm_pricing = $query->row();
This query solved my issue
$this->db->query(select * from product where product='A'
and subcategory='1'
union all
select * from product where product='A' and subcategory='3'
and not exists(select 1 from product where subcategory='1' and prodduct='A'));
Try using " group by productid " in your Query
I have 4 tables vendors, project,project_quotas and project_vendors
Table Structures:
vendors: id (Primary), name, email
project: id (Primary), name, status
project_quotas: quota_id (Primary), project_id (Foreign Key), quota_name, description
project_vendors: pv_id (Primary), project_id(Foreign Key), vendor_id, spec_quota_ids(comma separated, Foreign Keys), description
Lets Say For project_id = 1
I want to fetch All Project Quotas and their Project Vendors
here is Raw query I have created to get this data:
SELECT
pq.id as pq_id, pq.project_id as project_id, pq.name as pq_name, pv.id as pv_id, pv.vendor_id as pv_vendor_id, pv.spec_quota_ids as quotas
FROM `project_quotas` pq
LEFT JOIN
project_vendors pv ON pv.project_id = 1 AND find_in_set(pq.id, spec_quota_ids) > 0
WHERE pq.project_id = 1
GROUP BY pv.vendor_id, find_in_set(pq.id, spec_quota_ids)
Order BY pq.id
Here is the output
The only issue is that I want this query to Run Eloquent way.
I have ProjectQuota, ProjectVendors Model
I want something like
$data = ProjectQuota::where('project_id', '=', '1')->with('projectVendors', 'projectVendors.Source')->get();
I don't know how can I create a conditional hasManyrelationship in eloquent, will appreciate the help.
I this is the way to do this.
if($this->project_id===2) {
return $this->belongsTo(Foo::class);
}
if($this->project_id===3) {
return $this->belongsTo(Bar::class);
}
I'v staked with a one thing in laravel. I have huge database with those kinds of tables: products, categories and regions.
Products
id
category_id
region_id
Categories
id
parent_id = category.id or 0 if it is root
Region
id
parent_id = region.id or 0 if it is root
And I have to get all root regions who connected to specific category. The only solution I see it's to do it like this
$products = Category::products->all();
$rootCategories = [];
foreach($products as $product){
$rootCategories[] = $product->region->ultimateParent(); //Region::ultimateParent();
}
What do you think is there some kind of more eloquent way to solve it?
you have to use join like:
$query=DB::table('products')
->join('categorie','products.catagory_id','=','catagories.id')
->join('region','products.region_id','=','region.id')
->select('products.*','catagories.*',region.*'
->get();
This query will give you all the fields from all 3 tables.
I am new to laravel.
I have two tables.
1) products
2) prices
-----------------------------
- products -
-----------------------------
- id_product | int (p_key) -
- name | varchar -
-----------------------------
-------------------------
- prices -
-----------------------------
- id_price | int (p_key) -
- id_product | int -
- price | int -
-----------------------------
the products table holds data about products like id, name,...
the price changes are stored in prices table where the last record is the newest price that should be displayed to users.
now I want to search through products and get the last price of each product from prices table. this is my query:
$result = DB::table('products')->leftJoin('prices', function($join) {
$join->on('products.id_product', '=', 'prices.id_product');
})->whereRaw(MY_SEARCH_FILTERS);
the above code is wrong because if a product has 4 records in prices table, then it will be repeated 4 times in $result, but only 1 record with the last price should be displayed.
Here we have 2 tables users and answers where users is left table and answers is right table which has user answers.
We wanted to left join users with answers but the join should be with the latest record or answers table.
$query = Users::select('users.id', 'users.user_name','answers.created_at as last_activity_date')
->leftJoin('answers', function($query)
{
$query->on('users.id','=','answers.user_id')
->whereRaw('answers.id IN (select MAX(a2.id) from answers as a2 join users as u2 on u2.id = a2.user_id group by u2.id)');
})
->where('users.role_type_id', Users::STUDENT_ROLE_TYPE)->get();
you can make make it easy by using Laravel Elquent:
class Product extends Model
{
public function lastPrice()
{
// optional: change id_price to created_at by add created_at to prices table
return $this->hasOne(Price::class)->orderBy('id_price', 'DESC');
}
}
now in
public function getProducts(){
$MY_SEARCH_FILTERS=....;
// get all products with last price
$products=Product::with('lastPrice')->whereRaw(MY_SEARCH_FILTERS)->get()
return $products
}
Here we have 2 tables 'articles' and 'comments' where articles is left table and comments is right table which has article's comments.
We wanted to left join articles with comments but the join should be with the latest record from comments table.
$query = Article::select('articles.*', 'comments.comment as article_comment')
->leftJoin('comments', function($query) {
$query->on('comments.article_id','=','articles.id')
->whereRaw('comments.id IN (select MAX(a2.id) from comments as a2 join articles as u2 on u2.id = a2.article_id group by u2.id)');
})
->get();
i found this solution from here https://laravelcode.com/post/how-to-get-last-record-from-leftjoin-table-in-laravel
You need to add two things in here,
1) orderBy descending on prices table.
2) first clause in the DB::table function (It will fetch only 1
record, that will be the latest price).
The solution :
$result = DB::table('products')
->leftJoin('prices',function($join)
{
$join->on('products.id_product', '=', 'prices.id_product')
})->whereRaw(MY_SEARCH_FILTERS)
->orderBy('prices.id_price','desc')
->first();
You can also use (Laravel 5.1) :
$result = DB::table('products')
->leftJoin('products.id','=','prices.id_product')
->whereRaw(MY_SEARCH_FILTERS)
->orderBy('prices.id_price','desc')
->first();