This question already has answers here:
How do I specify unique constraint for multiple columns in MySQL?
(14 answers)
Closed 3 years ago.
I have two table both table are merge in third table like this
**sub_category**
Id
Name
**category**
ID
Name
**sub_cat**
ID
sub_id
cat_id
**category** **Sub_Category**
ID Name ID Name
1 One_Cat 1 one_sub
2 two_Cat 2 two_sub
3 three_Cat 3 three_sub
**Cat_SubCat**
ID Cat_id sub_catId
1 1 1
2 1 2
3 1 3
4 1 1
5 2 1
6 2 2
7 2 2
Do you See under cat_id 1 there is duplicate of sub_CatId,
and what i want is to validate that, under category one there should no duplicate subcategory same for category 2, there should no repeating subcategory under category 2
If you have uniqueness on your names in the category and subcategory tables, then it means that the IDs will be unique always.. So instead of validating if the relationship already exists you can simply use, sync() or syncWithoutDetaching() which will ensure that there will always be one connection between a category and subcategory, and no duplicates. Otherwise you use attach() which produces duplicates.
Take a look at the docs for more
https://laravel.com/docs/master/eloquent-relationships#updating-many-to-many-relationships
The migration should look like this:
Schema::create('sub_cat', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('sub_id');
$table->unsignedBigInteger('cat_id');
$table->unique(['sub_id', 'cat_id']);
});
the unique index ensures the sub_id and cat_id are unique.
And then whenever you want to add a sub-category use sync or syncWithoutDetaching.
But why you're designing the tables like that, you should just use a parent_id on category table
Schema::create('category', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('category');
$table->unsignedBigInteger('parent_id')->nullable;
$table->foreign('parent_id')->references('id')->on('category');
});
The Category model then should look like this:
class Category extends Model
{
public function parentCategory()
{
return $this->belongsTo(self::class, 'parent_id');
}
public function subCategories()
{
return $this->hasMany(slef::class, 'parent_id');
}
}
Related
How to get only one value in the filament table for with hasMany relationship?
I have two DB tables:
products
id
sku
1
SKU_1
2
SKU_2
product_descriptions
id
product_id
translation_id
name
1
1
1
Opel
2
1
2
Vauxhall
In my Product model I have hasMany relationship
public function productDescriptions(): HasMany
{
return $this->hasMany(ProductDescription::class);
}
When I do Tables\Columns\TextColumn::make('productDescriptions.name') it return all values separated by comma. In my example "Opel, Vauxhall"
Is there any way to manipulate/mutate return value using callback? Let say, return only first value "Opel"?
You can use calculated states.
Tables\Columns\TextColumn::make('productDescriptions.name')
->getStateUsing( function (Model $record){
return $record->productDescriptions()->first()?->name;
});
I have 2 tables i.e. users and user_managers, with the following structure and data:
users
id
name
employee_number
1
Employee One
ACB1234
2
Employee Two
XYZ1234
3
Employee Three
EFG1234
4
Employee Four
HIJ1234
user_managers
id
user_id
manager_of_user_id
1
1
2
2
2
3
3
4
1
4
5
4
I want a recursive function to get the complete chain of the managers. For example, if query for user_id = 4, I should get the following result:
result
user_id
name
employee_id
comments
1
Employee One
ABC1234
user managed by 4
2
Employee Two
XYZ1234
user managed by 1
3
Employee Three
EFG1234
managd by user 2
5
Employee Five
JKL1234
manager of user 4
The table above is just for the clarification, I am looking for a recursive function to get the above result.
I have tried the below solution but it is working for only 1 level.
public static function getCompleteChain(User $user)
{
$managerUsers = $user->managers;
foreach ($managerUsers as $manager) {
$manager->user = User::where('employee_id', $manager->manager_of_user_id)->first();
self::getCompleteChain($manager->user);
}
return $managerUsers;
}
Thanks in advance.
CONTEXT
I am managing products. This is a shoe store. I would like to offer a view of the other variants.
The database is shaped like this:
For example you can have a leather shoe (id 1), and there is 3 variants of this shoe: a black (id 1), a brown (id 2), and a grey (id 3).
What I try to do is to construct a Laravel relationship to be able, from one variant, to get its siblings. Here is what it looks like in the database according to the example I mentioned.
SHOE
id
====
1
SHOE_VARIANT
id shoeId colorId
===================
1 1 1
2 1 2
3 1 3
...
8 2 5
9 3 2
10 3 4
In this case, if the user is viewing the black variant (id 1), I whish I could show him the 2 others variants (brown, id 2, and grey, id 3).
QUESTION
How can I construct a Laravel relationship in order to retrieve siblings from a parent id, and make sure the current record itself is not included?
EXPERIMENTS
I already tried to construct a relationship like below, but the current record itself is included and I can't figure out how to exclude the record itself because I did not find how to get the current id of the record.
// app/ShoeVariant.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ShoeVariant extends Model {
public function siblings() {
return $this->hasMany("App\ShoeVariant", "shoeId", "shoeId");
}
}
This means:
For the current shoe variant, get the shoe variants that matches knowing that you should match the foreign column named "shoeId" and the local column named "shoeId"
So if 2 shoe variants share the same column "shoeId", this works. Stuck in excluding the current record from these results.
This should do what you want:
public function siblings() {
return $this->hasMany('App\ShoeVariant', 'shoeId', 'shoeId')
->where('id', '!=', $this->id);
}
Just filter out the current variant by id and get all the others.
Alternatively, you can just make a new property:
public function getVariantsAttribute() {
return $this->siblings->reject(function($elem) {
return $elem->id == $this->id;
});
}
And then use it in code like:
$variants = $model->variants; // all except this one
I have a channel_members table containing channel_id, user_id. I need to get the channel_id if there are multiple rows using that same channel_id which contains multiple user_id that I will provide.
Example:
If there are 5 rows in the table
CHANNEL_ID | USER_ID
2 | 2
2 | 3
2 | 4
3 | 2
3 | 4
I need to get the channel_id which are being used by user_id 2, 3, and 4. So based in the table above that I provided. I should get channel_id 2.
I assume you have already defined your relations uisng models, As per your provided description, channel has many to many relation with user
class Channel extends Model
{
public function members()
{
return $this->belongsToMany('App\User', 'channel_members', 'channel_id', 'user_id');
}
}
Using eloquent realtions you can check existance of related models as
$channels = App\Channel::whereHas('members', function ($query) {
$query->where('id', '=', 2);
})->whereHas('members', function ($query) {
$query->where('id', '=', 3);
})->whereHas('members', function ($query) {
$query->where('id', '=', 4);
})->get();
Above will return you only channels who have associations with all 3 users based on supplied id
Querying Relationship Existence
SELECT CHANNEL_ID
FROM channel_members
WHERE USER_ID in (2,3,4)
GROUP BY CHANNEL_ID
HAVING COUNT(CHANNEL_ID) > 0
I have two models that are related to each other with a belongsToMany relationship. The models are Game and Category. Of course, the tables for both are games and categories. The Category model, has its own parent-child relationship.
Basically this is my "simplified" structure:
Table game:
id unsigned integer
name string
Table categories:
id unsigned integer
name string
parent_id unsigned integer nullable
The parent_id column is null when the category has no parent, but it has an existing id referencing a row in the same table if it is a children of some other category.
Table category_game
category_id unsigned integer
game_id unsigned integer
The category_id column, references id on categories table. It should reference only the top category that a game belongs to. A game can belong to many different categories, but in the pivot table, there should only be a reference to the parents categories. For example if I had this structure of categories:
Category 1
Category 2
Category 4
Category 3
Category 9
Category 5
Category 6
Category 7
Category 8
I would like to have the following information for my games 1 and 2:
category_id game_id
3 1
5 1
1 2
And that should mean that my game 1 has categories: 3, 9, 5, 6, 7 and 8.
While my game 2 has categories: 1, 2, 4, 3 and 9
I understand that my Laravel models should have this:
class Game {
public function categories(){
return $this->belongsToMany( Category::class );
}
}
class Category{
public function games(){
return $this->belongsToMany( Game::class );
}
}
But I don't know how to retrieve the children categories using Eloquent. I know the belongsToMany method has more parameters that might help with my problem, but I don't know how to use them.
Model categoryGame for table category_game
class CategoryGame{
public function childCategories() {
return $this->hasMany(Category::class, 'parent_id','category_id');
}
}
You can access
$games = App\CategoryGame::all();
foreach ($games as $game ) {
foreach ($game->childCategories as $category) {
echo $category->name;
}
}
Let me know if not works
Extend your models:
class Category {
public function children() {
return $this->hasMany(Category::class, 'parent_id');
}
}
class Game {
public function getAllCategoriesAttribute() {
$result = collect();
$children = function($categories) use(&$result, &$children) {
if($categories->isEmpty()) return;
$result = $result->merge($categories);
$children($categories->pluck('children')->collapse());
};
$children($this->categories);
return $result;
}
}
Then you can access the categories like this:
Game::find($id)->allCategories;