How to merge two eloquent and load relationships - laravel

How can I merge two eloquent collections without losing any data and load relationship after that?
//I have two collections
$e1=Colour::find(1,3,7);
$e2=Colour::find(31,33,88);
//I need the following output
$merged=$e1->merge($e2)->load('relation');
When I performed the above merge, the first collection overwrites the second.
Please, give me a solution.

Push elements of $e2 to $e1 collection then use $e1 as you see fit.
foreach ($e2 as $e) {
$e1->push($e);
}
$e1->load('relation');

Use Laravel Collections
https://laravel.com/docs/5.7/collections#method-put
Code Example:
$collection = collect(['value' => $e1->value]);
$collection->put('value', $e2->value);
$collection->all();

Related

Best approcah for getting the object in the foreach loop in laravel using eloquent?

I have some properties and i want to get the object for each property, currently, I am using the eloquent in the foreach loop like this as shown in the image that will describe the best..
but it is really not a good approach because if I have 100 published property I will making 100 calls to the DB... and that is not correct?
I need a suggestion and a proper solution to this query?
Thanks in advance
Before foreach you can get all the RentalProperty items from db like this:
$allRentalProperties = RentalProperty::all();
and in foreach loop you can get those items without connecting database like this:
$propertyObj = $allRenatalProperties -> where('id', $property['id']) -> first();
Also, you can use array shorthand.
$newArray = [];
it's much simple and readable.
You can do array pluck before loop:
$propertyIds = Arr::pluck($published_properties, 'id');
Then you can make a whereIn query to get only those data which are in $published_properties object
$propertyObj = RentalProperty::whereIn('id', $propertyIds);
Then you can access that object with id if you change array key with record id.

Is Laravel sortBy slower or heavier to run than orderBy?

My concern is that while orderBy is applied to the query, I'm not sure how the sortBy is applied?
The reason for using sortBy in my case is because I get the collection via the model (i.e. $user->houses->sortBy('created_at')).
I'm just concerned about the performance: is sortBy simply looping each object and sorting them?, or is Laravel smart enough to simply transform the sortBy into an orderBy executed within the original query?
You need orderBy in order to perform a SQL order.
$user->houses()->orderBy('created_at')->get()
You can also eager load the houses in the right order to avoid N+1 queries.
$users = User::with(['houses' => function ($query) {
return $query->orderBy('created_at');
}])->get();
$orderedHouses = $users->first()->houses;
The sortBy method is applied to the Collection so indeed, it will looping each objects.
The orderBy() method is much more efficient than the sortBy() method when querying databases of a non-trivial size / at least 1000+ rows. This is because the orderBy() method is essentially planning out an SQL query that has not yet run whereas the sortBy() method will sort the result of a query.
For reference, it is important to understand the difference between a Collection object and a Builder object in Laravel.
A builder object is, essentially, an SQL query that has not been run. In contrast, a collection is essentially an array with some extra functionality/methods added. Sorting an array is much less efficient than pulling the data from the DB in the correct format on the actual query.
example code :
<?php
// Plan out a query to retrieve the posts alphabetized Z-A
// This is still a query and has not actually run
$posts = Posts::select('id', 'created_at', 'title')->orderBy('title', 'desc');
// Now the query has actually run. $posts is now a collection.
$posts = $posts->get();
// If you want to then sort this collection object to be ordered by the created_at
timestamp, you *could* do this.
// This will run quickly with a small number or rows in the result,
// but will be essentially unusable/so slow that your server will throw 500 errors
// if the collection contains hundreds or thousands or objects.
$posts = $posts->sortBy('created_at');

select certain columns from eloquent collection after the query has executed

Using Laravel 5.3, I have a model with the following function
public function myData() {
return $this->hasMany(MyData::class);
}
and in my collection I have the following
$my_data = MyModel->myData()->get();
All good so far. If I return $my_data I get an eloquent collection with three items.
What I need now though is to create a duplicate of that collection but containing only three of the fields.
I have tried several different things, each of which return an error. The following is the closest I have got, but this returns an empty array - I assume because the fields are located one level deeper than the collection object.
$new_collection = $my_data->only(['field_1', 'field_2', 'field_3']);
What would be the correct way to create a new collection containing all three items, each with only the three selected fields?
Thanks for your help
You could use map:
$slimmed_down = $collection->map(function ($item, $key) {
return [
'field_1' => $item->field_1,
'field_2' => $item->field_2,
'field_3' => $item->field_3
];
});
This will return a new Collection with just the values you want. As far as I know there isn't any other method that does what you want, so iterating over every item and selecting the fields this way is one of the few solutions.
The advantage of using map instead of a standard foreach loop is that when you use map it returns a new instance of Collection.
Edit:
After some thoughts and research about this, the problem you'll have created is that the all the values in the Collection aren't instances of anything anymore. If you don't mind this effect, an even prettier and faster way would be to do this:
$slimmed_down = $collection->toArray()->only(['field_1', 'field_2', 'field_3']);
This basically has the same result.
Using Laravel 9, I just had the same issue :
$my_data->only(['field_1', 'field_2', 'field_3']);
returning an empty array.
I solved it with :
$my_data->map->only(['field_1', 'field_2', 'field_3']);

FuelPHP: ORM Sort by HasMany Count

I have a table called post that HAS MANY comments I need to sort the list of post by how many comments there are in a post.
In fuelPHP, is there a way to do this in ORM? I want to make sure before I do it manually.
Thanks.
Short answer for this: No, there's not. It is not possible for the ORM to sort for you like that without doing it manually.
To work around it:
// construct an array with post-id => comment-count
$ordered = array();
foreach($posts as $id => $post)
{
$ordered[$id] = count($post->comments);
}
// order the array, largest count first
arsort($ordered, SORT_NUMERIC);
// merge the posts in, maintaining order
$ordered = array_replace($ordered, $posts);
This uses takes advantage of the feature that array_replace will maintain the key order of the first array.

Querying a one to one relationship from a collection

The problem is I need to pull a collection from a collection. I have already set up the models and database so these relationships work:
A User can have many Negotiations
A Negotiation has one RiderNegotiation
However I can't perform this query:
$user->negotiations->riderNegotiation
I thought I could get around this in my view file if I just passed off $user->negotiation and then parse through the negotiations. I discovered I can't use isEmpty() this way however.
#if($negotiations->riderNegotiation->isEmpty()
Is there some kind of nifty trick in Laravel to do this kind of relationship querying? I feel like this is a common issue.
hasMany returns a Collection of elements and you can't call hasOne on a Collection.
You should be able to do:
$negociations = User::find(1)->negotiations;
#foreach($negociations as $negociation)
echo get_class($negociation->riderNegotiation); //riderNegotiation
#endforeach
$negotiations = User::find(Auth::user()->id)->negotiations;
$temp = array();
foreach($negotiations as $negotiation ) {
$temp = array_merge($temp,$negotiaton->riderNegotiation->toArray());
};
A little resource expensive but $temp should contain all rider negotiations for that user.

Resources