Array_unique on a laravel eloquent collection - php

Not sure if this is possible but im trying to run array_unique over a collection of items i have, to remove duplicates. Although i cannot get it working.
my controller logic:
// init models
$jobs = Job::search();
$countries = $jobs->get()->map(function( $job ) {
return $job->country;
});
$countries = array_unique( $countries->toArray() );
although this gets a "Array to string conversion" error

You could try the Unique method of the Collection class:
$countries = $countries->unique();
The Collection class has several wonderful methods. You could read about this in the Laravel API documentation.
I agree that sometimes it is more efficient to "query" on an existing Collection in memory (in stead of doing another query on the database using the Querybuilder class), like for example you first want to count and then filter. In .NET LINQ you can query almost equally on an IEnumerable (in-memory collection) as on a database, something I really enjoy.

I had similar issue and although time have passed since it may be useful to someone today.
The Problem I had was that when I called unique method on collection of items it didn't worked, that is probably the reason the first answer got accepted. So if you have models and you want to remove duplicates based on a specific field you can pass parameter to your unique method, in this case it would be:
$countries->unique('code');
that way you'll only have countries with unique codes. You may notice that only the first value stays, so if you develop a shopping cart application and want for some reason merge carts and only want to have recent items you can just reverse the collection and call unique and reverse it back:
$countries->reverse()->unique('code')->reverse(); // it doesn't really make sense in this example though
it is probably not the best option and it is better to do filtering on the database side but it is nice to have options.

You can have unique values in your DB results using distinct or group by in your select clause. But, if you really need to have unique values over an array of object you can do the following:
$uniques = array();
foreach ($countries as $c) {
$uniques[$c->code] = $c; // Get unique country by code.
}
dd($uniques);

You could try the filter method on eloquent collections if that's exactly what you want to do
http://laravel.com/docs/eloquent#collections

Related

Can't get result from where condition with variables in laravel

this is how i'm trying to get the type of certificate with where condition , but still recieve
nothing from this query:
$res= student::find($student, ['typecertificate']);
$k = certificate::select('id-cer')->where('name-cer','=',$res)->get();
return $k;
Based on your comments, I'm assuming you want to retrieve the field certificateType from the latest record that was inserted in the students table.
You can achieve that without a where clause, by directly using the Eloquent Builder to retrieve only that specific field like this:
Student::latest()->first('certificateType');
But this would give you an Eloquent Collection with one element. If you just want the value (not wrapped in a collection), you can simply retrieve the latest student and get the corresponding field directly:
$certificateType = Student::latest()->first()->certificateType;
I could explain more, but your question is vague and your database schema isn't clear either, so I'd need more information on that as well as what you intend to achieve.
In any case, Laravel's documentation is often a big help: https://laravel.com/docs/9.x/eloquent#retrieving-single-models

How to sort a Cakephp query using a post calculated field and pass it to the paginate?

Have a formatResults callback function that adds a "custom calculated" field into the entities post returned from a model query in my Cakephp. I would like to sort by this field and use this on a paginate is this possible?
So far i cannot accomplish this because the paginate limits the records fetched and therefore only records less than the paginator limit get sorted and not all the resultset...
Current code:
$owners = $this->Owners->find('all');
$owners->formatResults(function (\Cake\Collection\CollectionInterface $owners) {
$owners = $owners->map(function ($entity) {
$entity->random = rand(0,1);
return $entity;
});
return $owners->sortBy(function ($item){
return $item->random;
},SORT_DESC);
});
This works as expected:
$owners->toArray();
This does not:
$owners = $this->paginate($owners);
$owners->toArray();
Mainly because its "callback processing" only the first 10 records, i would like to process the whole resultset.
After diggin around ive found a similar topic opened by a previous user on the this link, it seems that is not possible to use pagination sort in other than the fields in the database.
As a result, i would suggest:
1 - Either alter your model logic, to accommodate your requirements by creating virtual fields or alter database schema to include this data.
2 - If the data requires further or live processing and it cannot be added or calculated in the database, perhaps programming a component that will replicate the paginate functionality on a cakephp collection would be a good option.The downside of this approach is that all records will be returned from the database which may present performance issues on large resultsets.

Doctrine Query Builder : Result returning array of two times the same result

I'm currently working on a Symfony project, using Doctrine to manage entities.
I have a table named User, containing a few columns, and then another table named Tag, containing a foreign key to that User table with a ManyToOne relation based on the user id, and a single other column named value.
In my app, I need to find a list of users, depending on one of the Tag row, AND the value of one of the User's column. Let's resume :
Select all users where user.value equals somevalue AND Tag.value equals anothervalue.
As I never used Symfony nor Doctrine before this project, I searched into Doctrine documentation and found about the Query Builder. So, I did this :
EDIT : The way I was doing it was kinda weird, so I modified it and here is the result :
public function findByTagAndApp($tag, $app)
{
$em = $this->getEntityManager();
$qb = $em
->getRepository('APIBundle:User')
->createQueryBuilder('u')
->leftJoin('APIBundle\Entity\Tag', 't')
->where('u.application = :app')
->andWhere('t.tag = :tag')
->setParameter('tag', $tag)
->setParameter('app', $app)
;
$users = $qb->getQuery()->getResult();
return $users;
}
And it seems like it works, but in a strange way. Instead of returning an array of User items, which is what I want, it returns an array of array of User items. The first array is always containing two entries, and these two entries are always identical : they are the array I need, without a single difference.
I tried to do return $users[0] instead of just users, and then I can manipulate my User entities the intended way. I could keep it this way as it is working, but I'd really like to know why it returns an unneeded array of array instead of just the array I want. It might be my query, but I'm not sure how to modify it to get only the Users I want.
Any clues on why it behave like this would be really appreciated, as I'm still learning about Doctrine. Thanks !
EDIT² : Nevermind, this query seems completely incorrect too, as I got all users according to the $app value, but it seems like it never check if there is a row in the Tag table with a value of somevalue associated to a foreign key of the User table..
I don't know exactly why it is but..
I think you have to mention from() like ->from('User', 'u')
for extra you can find here
After a few hours of tweaking, I figured it out using SQL statement on PhpMyAdmin, so I could notice that there was a LOT of things that I was doing wrong :
First, the join was not correct. My goal was to collect users that had a certain value in their own table, AND a value from the Tag table. Using a left join, I was collecting users with their own value OR a the value from the Tag table.
Second : The $app value I was passing was an object of type Application (the Application field in my User table is a foreign key), and the query builder didn't know what to do with it. Passing the app_id instead of the app object solved the problem.
Third : The way I collected result was wrong. Obviously, this query returns an array of User objects. And as I execute this query multiple times in a row, I had an array on which I used array_push to fill it with the data, thinking that pushing array1 with array2 would put array2 values into array1, but it was just putting array2 into array1, resulting to that array of arrays that was the initial problem. Using array_merge instead of array_push, I am now able to collect all the results from the queries into a single array. A little array_unique on that to avoid redundancy, and everything is working as expected.
Thanks to everyone who replied !

Remove last two rows in a Laravel Collection Object

I am trying to remove the last two row in a Laravel Collection. The size of the Collection can vary, but I will always want to remove the last two. I managed it by doing this, but out of curiosity, do you think there is a better way to do this ?
Here is my way :
$results = $results->reverse()->slice(2)->reverse();
Thanks a lot
John
The Collection object's slice() method works similarly to array_slice(), allowing a negative value for the length argument, so you should be able to keep it simple and just do
$results = $results->slice(0, -2);
You can use the pop method twice.

Query Laravel Result Set

I am looking to do several queries using eloquent which are all to be returned to a single view and was wondering if there was a better way to do it than querying the database multiple times?
For example returning all the records then pulling sub sets of data from that?
At the moment I have something similar to:
$one = User::queryOne();
$two = User::queryTwo();
$three = User::queryThree();
etc
However I was thinking it would be better if it was possible to do something like:
$users = User::all();
$one = $users->where('created_at')...
$two = $users->where('modified_at')..
Obviously the above doesn't work but it it possible to do something like this?
Or is it best just to query the database separately each time?
From a pragmatic point of view, it's 'better' to do multiple queries, because it takes you less time to write them, and they are easier to read and debug. If you want to do it with one DB query, and then grabbing subsets out of them, you'd have to write your own convoluted logic, or perhaps a new Laravel collection class. And then someone else comes along and wonders, "What is going on in this code?"
Typically programmer time is the most constrained resource in a project. When you get done, if you find that the multiple database queries are a bottleneck, then think about re-writing it.
If you do decide to do one query, you can probably order the data by the fields you want for the criteria. Then loop through the result set, adding the rows to a new array each time the specified field's value changes. That's the simplest logic I can think of offhand.
What version of laravel are you using? In 5.1 you can do where on collections here. In 4.2 you can do so with callbacks here
EDIT
for 4.2 try something similar to this
$users = User::all();
$one = $users->filter(function($user)
{
if($user->age > 20){
return true;
}
return false;
});
Laravel Eloquent returns a Collection as a result.
You could use a foreach statement or use the build in Collections functions you could manipulate the results and create the sub-results.
For example you could use filter and do something like this:
$users = User::all();
$one = $collection->filter(function ($item) {
return $item->created_at >= time() - (24*60*60); // created the last day
});
$filtered->all();
Whether it is the best method depends on the application and the amount of data you are trying to fetch/process.
If you have only a few records from ::all(), then doing so might be a good approach (although using the collections functions you have to run three filters across your data).
If you have a lot of records from ::all() then it is preferably to use three different queries to the database (especially if the results will only be a few records).

Categories