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);
I have two db tables: exercises and schedules. The relation between them is a many to many.
I have some data stored in the pivot table. When i return the table i don't want id to be shown, because it is a useless repetition. The code i'm using:
$results = Schedule::with(['exercises', 'exercises.tags'])->where('user_id', Auth::user()->id)
->get();
$results->each(function ($schedule) {
$schedule->exercises->each->makeVisible('pivot');
});
I tried this approach, but it doens't seem to work:
$results = $results->toArray();
foreach ($results as $schedule) {
foreach ($schedule['exercises'] as $exercise) {
unset($exercise['pivot']['schedule_id']);
unset($exercise['pivot']['exercise_id']);
}
}
I know the question may not be much clear, sorry for that but my english is not the best.
Use the eloquent makeHidden method:
$results = $results ->makeHidden(['exercises.pivot.schedule_id']);
source: https://laravel.com/docs/8.x/eloquent-collections#method-makeHidden
I am retrieving users using many to many relationships. I want to loop through the user only one time that have two entries in pivot.
e.g.
$admin = Admin::first();
$users = $admin->users;
foreach($users as $user) {
//Iterate through users that has different ids
//Do not iterate over same user twice
}
Nothing wrong with your code just use all() OR get() instead of first().
Or if you have multiple entries with single admin please share your model code
If you dont need the duplicate user entries, it is also possible to avoid the duplicates in the $admin->users collection by using the distinct method:
$admin = Admin::first();
$users = $admin->users()->distinct()->get();
https://laravel.com/docs/5.5/queries#selects
I found the solution myself. array_unique($array) was the solution. I pushed user ids to $users array and used array_unique($users).Thanks to php.net.
Ref. http://php.net/manual/en/function.array-unique.php
<?php
$input = array(4, "4", "3", 4, 3, "3");
$result = array_unique($input);
var_dump($result);
?>
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();
I have a questions table and a tags table. I want to fetch all questions from tags of a given question. So, for example, I may have the tags "Travel," "Trains" and "Culture" attached to a given question. I want to be able to fetch all questions for those three tags. The tricky, so it seems, is that questions and tags relationship is a many-to-many defined in Eloquent as belongsToMany.
I thought about trying to merge the questions Collections as below:
foreach ($question->tags as $tag) {
if (!isset($related)) {
$related = $tag->questions;
} else {
$related->merge($tag->questions);
}
}
It doesn't seem to work though. Doesn't seem to merge anything. Am I attempting this correctly? Also, is there perhaps a better way to fetch a row of rows in a many-to-many relationship in Eloquent?
The merge method returns the merged collection, it doesn't mutate the original collection, thus you need to do the following
$original = new Collection(['foo']);
$latest = new Collection(['bar']);
$merged = $original->merge($latest); // Contains foo and bar.
Applying the example to your code
$related = new Collection();
foreach ($question->tags as $tag)
{
$related = $related->merge($tag->questions);
}
The merge() method on the Collection does not modify the collection on which it was called. It returns a new collection with the new data merged in. You would need:
$related = $related->merge($tag->questions);
However, I think you're tackling the problem from the wrong angle.
Since you're looking for questions that meet a certain criteria, it would probably be easier to query in that manner. The has() and whereHas() methods are used to generate a query based on the existence of a related record.
If you were just looking for questions that have any tag, you would use the has() method. Since you're looking for questions with a specific tag, you would use the whereHas() to add the condition.
So, if you want all the questions that have at least one tag with either 'Travel', 'Trains', or 'Culture', your query would look like:
$questions = Question::whereHas('tags', function($q) {
$q->whereIn('name', ['Travel', 'Trains', 'Culture']);
})->get();
If you wanted all questions that had all three of those tags, your query would look like:
$questions = Question::whereHas('tags', function($q) {
$q->where('name', 'Travel');
})->whereHas('tags', function($q) {
$q->where('name', 'Trains');
})->whereHas('tags', function($q) {
$q->where('name', 'Culture');
})->get();
$users = User::all();
$associates = Associate::all();
$userAndAssociate = $users->merge($associates);
Merge two different eloquent collections into one and some objects happen to have the same id, one will overwrite the other. Use push() method instead or rethink your approach to the problem to avoid that.
Refer to web
Creating a new base collection for each eloquent collection the merge works for me.
$foo = collect(Foo::all());
$bar = collect(Bar::all());
$merged = $foo->merge($bar);
In this case don't have conflits by its primary keys.
I have faced some issue by using merge. So I used concat. You can used it like below.
$users = User::all();
$associates = Associate::all();
$userAndAssociate = $users->concat($associates);
All do not work for me on eloquent collections, laravel eloquent collections use the key from the items I think which causes merging issues, you need to get the first collection back as an array, put that into a fresh collection and then push the others into the new collection;
public function getFixturesAttribute()
{
$fixtures = collect( $this->homeFixtures->all() );
$this->awayFixtures->each( function( $fixture ) use ( $fixtures ) {
$fixtures->push( $fixture );
});
return $fixtures;
}
I'm sorry about that, but since PHP 7.4 you're available to do like this (better use merge).
$foo = Foo::all();
$bar = Bar::all();
/** $foo will contain $foo + $bar */
$foo->push(...$bar);
I would like to add that, i found that the concat method does not seem to override based on ID, while the merge method does. concat seems to work for me, while merge caused issues.