I have a many to many relationship between categories and products tables.
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ categories │ │ products │ │ category_product │
├─────────────────┤ ├─────────────────┤ ├──────────────────┤
| id | | id | | shop_id |
| name | | name | | category_id |
| created_at | | price | | product_id |
└─────────────────┘ | created_at | | created_at |
└─────────────────┘ └──────────────────┘
Category model:
class Category extends Model
{
public function products()
{
return $this->belongsToMany(Product::class);
}
}
Product model:
class Product extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
Because I'm using the cetegory_product table to also map the shop. I have some problem with getting the distinct results. let's just say that I have the following records in the pivot table:
shop_id | category_id | product_id
--------------------------------------
1 |18 |4
1 |18 |5
Now when I try to get the categories for a shop or the reverse relationship like this:
$shop = Shop::find(1);
$shop->categories()->get();
I get duplicated data.
So I like to know how can I perform a distinct select for categories?
BTW: I tried to add a scope on each model, adding the distinct to the query, but it did not work.
Unless I'm missing something you should be able to use groupBy().
$shop = Shop::find(1);
$shop->categories()->groupBy('category_id')->get();
$shop->categories()->distinct()->get();
Related
I'd like to export data from my database but have problems with multiplying and sum using laravel eloquent with relation
So i have 2 tables there (budgets, items)
Budget's:
// Table
+----+---------------+-----------------+------+-----+--------------------+
| id | delivery_plan | item_code | curr | qty | price |
+----+---------------+-----------------+------+-----+--------------------+
| 1 | 2022-08 | 201.0001 | IDR | 1 | 2000.0000000000 |
| 2 | 2022-08 | 201.0001 | IDR | 3 | 2000.0000000000 |
| 3 | 2022-07 | 201.9999 | IDR | 2 | 2000.0000000000 |
+----+---------------+-----------------+------+-----+--------------------+
// Relation
public function item()
{
return $this->belongsTo(Item::class, 'item_code', 'item_code');
}
Items :
// Table
+----+----------------+-----------+
| id | subgroup | item_code |
+----+----------------+-----------+
| 1 | KOMPONEN MESIN | 201.0001 |
| 2 | EQUIPMENT LAIN | 201.9999 |
+----+----------------+-----------+
// Relation
public function budgets()
{
return $this->hasMany(Budget::class, 'item_code', 'item_code');
}
So, the scenario is :
Multiply the "qty" * "price" columns and name them as "total" like so
Group them by "subgroup" column, which came from item() relationship
Group them by "delivery_plan"
I prefer using eloquent because to minimize the complexity because i need that "whereHas" method
This is what i've tried so far and isn't working :
$budgets = Budget::with('item', 'rate')->whereHas('period.term', function (Builder $builder) {
$builder->where('name', '=', Session::get('term-budget'));
})->where('section', Session::get('section-budget'))->getQuery();
$result = $budgets->sum('price * qty')->get();
How can i achieve this ?
This can be solved by a join with SUM(), something like below (untested):
Budget::leftJoin('items', 'budgets.item_code', '=', 'items.item_code')
->addSelect('subgroup')
->addSelect('delivery_plan')
->addselect(\DB::raw('SUM(qty * price) as total'))
->groupBy('subgroup', 'delivery_plan')
->get();
"language" table
id | name | code
-------------------
1 | English | en
2 | German | de
"article" table
id | is_active
--------------
1 | 1
2 | 1
"article_translation" table
article_id | language_id | title
-------------------------------------------
1 | 1 | foo
1 | 2 | title1 in German
2 | 1 | title2 in English
2 | 2 | foo
Suppose I search "foo" with like condition, and I want to get the results with language_id = 1 but still need to search the title on other languages. The following results as I expected:
article_id | language_id | title
-------------------------------------------
1 | 1 | foo
2 | 1 | title2 in English
In laravel, I tried to use group by function but the results can't make sure that the language_id is 1. Also, it need to set the strict mode to false.
\App\ArticleTranslation::where('title', 'like', '%foo%')->groupBy('article_id')->paginate(10);
SELECT at1.*
FROM article_translation at1
JOIN article_translation at2 ON at1.article_id = at2.article_id
WHERE at2.title = #title
AND at1.language_id = #language_id
fiddle
PS. Convert to Laravel by yourself...
Add relations for easy queries
// Language model
public function articles()
{
return $this->belongsToMany(Article::class);
}
// Article model
public function languages()
{
return $this->belongsToMany(Language::class);
}
// in controller
$articles = Language::find(1)->articles()->wherePivot('title', 'like', '%foo%')->get();
foreach($articles as $article){
dump($article); // $title = $article->pivot->title
}
please help..
I have 2 tables
Current user_id = 3
Users Table:
| user_id | email | name |
-------------------------------------------
| 1 | one#gmail.com | ridwan |
| 2 | two#gmail.com | budi |
| 3 | six#gmail.com | stevan |
| 4 | ten#gmail.com | agung |
Relations Table [ user_id and follower_id are related to Users Table ]
| relation_id | user_id | follower_id |
-----------------------------------------
| 1 | 1 | 3 |
| 2 | 2 | 3 |
i want to get the list of the user, but if i already have relation with a user, it will give me a status 'following', just like instagram, maybe look like this
{
user_id : 1,
name : ridwan,
status : following
},
{
user_id : 2,
name : budi,
status : following
},
{
user_id : 4,
name : agung,
status : not following
}
how can i do that in laravel?
thank you..
In your Relations model
public function user()
{
return $this->belongsTo(User::class);
}
Then, in your controller (where you want to get this list), you just need to use Eloquent or Query Builder to get what you want (with eager loading, it's always better) :
//get all users related to your_current_user
$relations = Relation::where('follower_id', your_current_user_id)->with('user')->get();
Finally, you just have to make manipulate your data like you want, for example :
foreach($relations as $relation){
$relation->user->name; //get the name of the related user
}
Take a look at Relationships !
Thank you guys.. finally I use sql case, i was only confusing about how to get the data with 'following' status
here is the code:
DB::table('users')->leftjoin('relationships', 'users.user_id', '=', 'relationships.user_id')->select('users.user_id','users.status as user_type','users.email','users.display_name','users.profile_image',DB::raw('(CASE WHEN relationships.follower_id = ' . $user_id . ' THEN "Following" ELSE "Not Following" END) AS status'))->orderBy('user_id','asc')->where('users.user_id','!=',$user_id)->get();
Items Table
| id | item_id | item_title |
|-------|---------|------------|
| 1 | 1002 | A |
| 2 | 1003 | B |
| 3 | 1004 | C |
Sells Table
| id | item_id |
|----|-----------|
| 1 | 1002 1003 |
| 2 | 1003 1004 |
| 3 | 1004 1002 |
I want result : Sells Table 1. item title is A B
I want to combine the sells table with the item table and then match the item_id of the sells table to the item_title of the item table.
The table definitions look incorrect, you should have a pivot table linking items with sells, so a sell_item table:
item_id | sell_id
-----------------
1 | 1
1 | 3
2 | 1
2 | 2
3 | 2
3 | 3
Then using eloquent, you'd create models to represent your tables and define the relationships using BelongsToMany:
class Item extends Model {
public function sells() {
return $this->belongsToMany(Sell::class);
}
}
class Sell extends Model {
public function items() {
return $this->belongsToMany(Item::class);
}
}
Each instance of either model will then have access to it's related models via $item->sells and $sell->items.
The query builder can perform a join if not going the Eloquent route:
DB::table('sells')->join('items', 'sells.item_id', '=', 'items.item_id')
->select('sells.*', 'items.title')
->get();
The table definitions look incorrect, If you corrected already then your model replationship should be like
class Item extends Model {
public function sells() {
return $this->belongsToMany(Sell::class);
}
}
class Sell extends Model {
public function items() {
return $this->belongsToMany(Item::class);
}
}
Each instance of either model will then have access to it's related models via $item->sells and $sell->items.
The query builder can perform a join if not going the Eloquent route:
DB::table('sells')->join('items', 'sells.item_id', '=', 'items.item_id')
->select('sells.*', 'items.title')
->get();
Or if your model name is Sell then
$response=Sell::with('items')->get();
I try to eager load a polymorphic model with some conditions that's connected to two other models and having some problems.
My models:
class One extends Model {
public function twos() {
return $this->hasMany(Two::class);
}
public function threes() {
return $this->morphMany(Three::class, 'threeable');
}
}
class Two extends Model {
public function one() {
return $this->belongsTo(One::class);
}
public function threes() {
return $this->morphMany(Three::class, 'threeable');
}
}
class Three extends Model {
public function threeable() {
return $this->morphTo();
}
}
So far everythings is everything great: I've a lot of One items that have a lot of Two relations and both have even more Three relations (on its own).
Now I try to get the latest Three from Two, where it also can come from a One relation (highest threes.updated_at from either A or B).
The threes table looks something like this
| id | threeable_id | threeable_type | updated_at |
|---|---|---|---|
| 1 | 1 | A | 1 |
| 2 | 1 | A | 2 |
| 3 | 1 | B | 3 |
| 4 | 1 | B | 4 |
| 5 | 2 | A | 2 |
| 6 | 2 | A | 4 |
| 7 | 2 | B | 1 |
| 8 | 2 | B | 3 |
I want threes.id = 4 for B::find(1)->withC() and threes.id = 6 for B::find(2)->withC().
For performance reasons I want to load it in one query (I'm loading multiple Two and want the related Three and don't want to fire an own query for that). So I tried to put it in a scope (in class Two). Joining on the Three table and doing some max on the updated_at in a sub query ... It was a total mess and didn't worked that well
It didn't really feel the "Laravel-way" neither :(
Thanks for any help
EDIT
Maybe as an addition here's the pure SQL
SELECT twos.id, threes.id
FROM
(SELECT
twos.id twoId, MAX(th.updated_at) threeMaxUA
FROM
twos
LEFT JOIN (SELECT
th.*
FROM
(SELECT
threeable_id, threeable_type, MAX(updated_at) AS updated_at
FROM
threes
WHERE
deleted_at IS NULL
GROUP BY threeable_id , threeable_type) thmax
LEFT JOIN
threes pr ON (th.threeable_id = thmax.threeable_id
AND th.updated_at = thmax.updated_at
AND th.threeable_type = thmax.threeable_type)
GROUP BY th.threeable_id , th.threeable_type) th
ON
(
(th.threeable_id = twos.id AND th.threeable_type = 'App\\Two')
OR
(th.threeable_id = twos.product_id AND th.threeable_type = 'App\\One')
)
GROUP BY twos.id
) twthmax
LEFT JOIN twos ON twos.id = twthmax.twoId
LEFT JOIN threes ON (
twthmax.threeMaxUA = threes.updated_at
AND
(
(threes.threeable_id = twos.id AND threes.threeable_type = 'App\\Two')
OR
(threes.threeable_id = twos.product_id AND threes.threeable_type = 'App\\One')
)
)