Is there an eager "inserting" option in laravel for ManyToMany attach? - php

Is there a way to reduce many Insert queries to 1 when using Laravel's attach function in ManyToMany relationship?
Here is my code:
$itemIds = Item::pluck('id');
$sale = Sale::create();
foreach ($itemIds as $id) {
$sale->items()->attach($id);
}
But this way it makes as many queries as items found in the database.

Attaching / Detaching
For convenience, attach and detach also accept arrays of IDs as input.
For example:
$user = User::find(1);
$user->roles()->attach([1, 2, 3]);
In your code, you have to use $itemIds as array of Item Id.
$itemIds = Item::pluck('id');
$sale = Sale::create();
$sale->items()->attach($itemIds);

Related

How to detach on many element with Laravel Eloquant

I have a relationship many to many with the table Screen and Media with a pivot table Media_Screen.
I want to remove the data with the screens' id in $id_screens from the pivot table.
I did like this :
$id_screens = [4,5];
$screens = App\Screen::whereIn('id', $id_screens)->get();
foreach($screens as $screen)
{
$screen->medias()->detach();
}
It works but I'm wondering if there is not a better way to do? I tried something like this but it didn't work :
$id_screens = [4,5];
$screens = App\Screen::whereIn('id', $id_screens)->get();
$screens->medias()->detach();
You can mass detach the relationship by querying on pivot table. It'll reduces number of queries you do in the loop. In your case, you can use below code for example.
$screens_id = App\Screen::whereIn('id', $id_screens)
->select('id')
->get()
->pluck('id');
\DB::table('Media_Screen')->whereIn('id_screen', $screens_id)->delete();
You may try "high order messages" as documented here:
$id_screens = [4,5];
$screens = App\Screen::find($id_screens);
$screens->each->medias()->detach();

how to compare two collection and get match records

I am using Laravel and I have two different collections that contain ID of products
First one is colorProduct and second is tagProduct
so I want to compare these two and get only same ID of products so how can I do this?
$colorProducts = Color::where('code', $request->color)->get()->first()->products;
$tagProducts = $tag->products->where('shop_id', $shop->id);
$colorAndTagProducts = collect();
foreach ($colorProducts->toBase()->merge($tagProducts)->unique('id')->groupBy('id') as $allProducts) {
if ($allProducts->count() >= 1) {
$colorAndTagProducts[] = $allProducts->first();
}
}
here
$colorAndTagProducts
gives me all records form both collection but I only want same record
I dont know, if I understand correctly, but maybe like this?
I suppose Color and Product are in many to many relationship. And Product and Shop/tag in one to many.
$colorId = Color::where('code', $request->color)->get()->first()->id;
$shopId = $shop->id;
$products = Product::whereHas('colors', function ($query) use ($colorId) {
$query->where('id', $colorId); //id or color_id
})->where('shop_id', $shopId)->get();
intersect()
The intersect method removes any values from the original collection
that are not present in the given array or collection. The resulting
collection will preserve the original collection's keys:
I did it with this method

Extract all possible values of AR column in yii2

Several models in yii2 are bound to a database using ActiveRecords. I now want to have a list of all ids of this model. Say, all user IDs when the Model is called User.
Sure I could just fetch all models and iterate over them, much like
$ids = [];
$users = User::find()->all();
foreach ($users as $user) {
$ids[] = $user->id;
}
But I feel there should be an easier way... Thanks in advance.
If you want to stay in ActiveRecord then this accomplishes the same thing:
$ids = User::find()->select('id')->column();
This returns array:
$ids = (new \yii\db\Query)->select('id')->from(User::tableName())->all();

Laravel relations, select next raleted row from database.

I have related items in my database. I selected all of items from database by related id:
$next_stock = $this->model->get()->where('part_id', $in_data['part_id'])->all();
and I collection of rows grouped by one specific id, like on the picture. All of them selected by "part_id":
Selection Of Items
Grouped By Same Id
Also with this line of code i can select one of the items from this collection:
$next_stock = $this->model->get()->where('id', $old_stock['id'])->where('part_id', $in_data['part_id'])->first();
But how can I select the following items after this one?
Or, how can I select second or third item from this collect?
I cannot just increase id number by one from first, because sometimes this item ids not following each other.
Having a collection, you can take a specific element in the position with a combination of take() and last().
$collection = $this->model->get()->where('part_id', $in_data['part_id'])->all();
$second = $collection->take(2)->last(); //if this doesnt work, do it in 2 steps
$third = $collection->take(3)->last(); //if this doesnt work, do it in 2 steps
If you don't have a collection, take directly from database like this
$second = $this->model
->where('part_id', $in_data['part_id'])
->skip(1)
->first();
If it doesn't work with first()
$collect = $this->model
->where('part_id', $in_data['part_id'])
->skip(1)
->take(1)
->get();
$second = $collect->first();
Edit
skip() and take() are actually part of the query builder, not eloquent model. So it won't work with Eloquent in Laravel 5.4
Try with
$collect = $this->model
->where('part_id', $in_data['part_id'])
->get(1); //For the second record, 0 being the first
If you aren't doing it yet, you should set your model's relationships.
E.g. If you use "one-to-many", Eloquent will automatically determine the proper foreign key column on the model for you.
$parts = App\Stock::find(1)->partId;
foreach ($parts as $part) {
//
}

(Laravel) only retrieving users that have a relationship

In my site I have users and items. Users can create items. I want to get an array that has all users, where the users which have an item go first and the users which do not have an item go after.
So far I have done this:
$users = User::all();
foreach($users as $user) {
if ($user->item) {
$sortedUsers + $user;
}
// now loop again and add users without relationship
This is pretty inefficient and I'm sure there's a much better way to do it.
You can query on the existence of a relationship
$users = User::has('items')->with('items')->get();
with that syntax you are telling laravel to fetch all users that have a item and to eager load the items;
Edit:
After reading it does not look like you actually want the items just the users that have a item in that case all you need is
$users = User::has('items')->get();
Without seeing the relation of Items to Users I'm not sure if this will work but you can try the following:
$users = Users::select('users.*')->orderBy('items.id')->with('items')->get();
Or it might work with just:
$users = Users::orderBy('items.id')->with('items')->get();
Update
$users = Users::orderBy('items.id')->join('items', 'items.user_id', '=', 'users.id')->get();
you can try
$users = User::with('item')->get();
foreach ($users as $user) {
echo $User->item->name;
}
You can use has() to get users with items and doesntHave() to get users without items:
$withItems = User::has('items')->get();
$withoutItems = User::doesntHave('items')->get();
And then merge() two collections:
$users = $withItems->merge($withoutItems);
You said you want an array, so you can convert result into an array with toArray()
$array = $users->toArray();

Categories