What is the different between laravel PLUCK and SELECT - laravel

I found that laravel 'pluck' return an plain array and 'select' return an object. Can anyone explain it to me have any other different between two this?
thank you.

Pluck is a Laravel Collections method used to extract certain values from the collection. You might often want to extract certain data from the collection i.e Eloquent collection.
While Select is a normal selection of either multi or specific columns. They are
By using Pluck you only ask to return necessary fields, but with get you will pull all columns. Also select does the same & the difference here is between the returning result. Using pluck cause returning the final result as an array with pair of given arguments, but select return an array (or object) which every single child contain one row.
$name = DB::table('users')->where('name', 'John')->pluck('name');

Select
EX : DB::table('users')->select('id', 'name', 'email)
Select is a method sent to the database that Laravel will translate as
SELECT id, name, email FROM users
This will select the data of the columns you asked and nothing else. It allows you to be more efficient with your request by only asking the required data. Take the example above and image that the user is a Facebook user. It has a ton of data on it, plus relations to other tables. If you just want to display the name, email and a link to the user profile, doing this request!
For more info and knowing more about the expected response visit : https://laravel.com/docs/9.x/queries#select-statements
Pluck
EX:
$users = DB::table('users')->where('roles', '=', 'admin')
$emails = $users->pluck('email')
The Pluck method retrieves the values in a collection that you already got from the Database and that is now a Laravel Collection. This allows you to create an array of the plucked data, but will not improve the performance of your request, as in the Example above, the $users would hold all data of all the admin users.
Since it does not improve performance, what good is it then ?
The pluck would be useful for example to separate some datas in different variables depending on where. You might need the users data for some stuffs, but also want to display a quick list of all emails together.
For more info about the pluck method and understand how to create a keyed array from a second column, visit the docs here: https://laravel.com/docs/9.x/collections#method-pluck

Pluck function normally used to pull a single column from the collection or with 2 columns as key, value pairs, which is always be a single dimension array.
Select will return all of the columns you specified for an entity in a 2 dimensional array, like array of selected values in an array.
Note: Pluck function is a collection function which happens after the data is fetched. Select is a query builder function that builds query to perform in the database server.

Actually select is used inside DB queries, which can affect the performance by limiting the pulled columns. However, Pluck is Laravel Collection's method, so you can use pluck after you pull the data from DB.

Related

Laravel get collection of created/updated rows

new to laravel.
My use case:
Update multiple rows (say: resources table).
Create multiple users (users table).
Retrieve ids of created users
What I currently did:
First, Update the resources table whereIn('id', [1,2,3,4]). (Update eloquent)
Second, Get array of the updated resources (Another eloquent: Resource::whereIn('id', [1,2,3,4])->get()->toArray())
Bulk create a users. Refers to the resources collection above. (Another eloquent: User::create($resources))
Lastly, get the ids of the created users (Not resolved yet. But I might have to use another eloquent query)
All in all, there are 4 Eloquent queries, which I want to avoid, because this might have performance issue.
What I wanted to do is that, On first step(Update), I should be able to get a collection of models of the affected rows (But I can't find any reference on how to achieve this). And then use this collection to create the users, and get the users ids in one query with User::create() so that I will have 2 queries in total.
There is no need to invent performance problems that do not exist.
Update or Insert return only count of affected rows. Commands Select, Insert, Update performed separately. This is a SQL issue, not Laravel.
For single inserts (if you want add one row) you can use insertGetId method of a model.
For example,
$id = User::insertGetId([
'email' => 'john#example.com',
'name' => 'john'
]);
But you get only ID of record. You need to run select to get full data of the row.
To save multiple records with one query you can use
DB::table('table_name')->insert($data);
Since this won't be an eloquent method, you should pass all the columns including created_at and updated_at.
I don't know what is the method name for update.

Eloquent Eager Loading in Cursor (Lazy Collection)

I'm trying to export a large number of records from my database, but I need relationship data in order to build the export correctly. Ideally I would be able to use cursor() to get a Lazy Collection, but that won't load the relationships. I can't load the relationship within a loop, because that will create N+1 queries, and this could be hundreds of thousands of additional queries, which is unacceptable.
Here's what "works" (but runs out of memory):
Record::with('projects')->get()->map(function ($record) {
dd($record); // Shows the `projects` relationship
});
But when I use cursor()...
Record::with('projects')->cursor()->map(function ($record) {
dd($record); // Does NOT show the `projects` relationship
});
Is there a way to get a lazy collection that includes a record's relationship? I have looked in the documentation and it's not clear. Other suggestions have been to use chunk() which is unfortunately not a possibility in this situation.
EDIT: I shouldn't say chunk isn't a possibility, but it's a very expensive re-write. Currently, the data is structured with a lot of variability. So in order to construct the CSV for export, I need (for example) a header for the file. I currently grab that header by looping through all the records (the fields are stored in a JSONB field) and building out an array based on the fields present on those records.
I am also normalizing the data against those headers. So if one record has the field "address-1" but another record doesn't have that, the one that doesn't have it instead shows a blank value in the appropriate column. Otherwise, when inserting the row into the CSV, it doesn't respect the header.
These operations currently grab the entire data set and use a LazyCollection to map the header and normalize the records, and then feed it into the CSV one at a time. It would be ideal if I could grab relationships in a LazyCollection as well rather than having to rewrite the workflow.
according to this doc
cursor work in db stage, while loading relations come after method 'get' or 'first' ...
so: the code in cursor will work in db row represented as Model instance before the overall result, means that this code will run into db, without loading the relation, again db row (iterate through your database records...)
if you can't use chunk... then i think that you can use mySql to manage your data using raw-expressions

How to Paginate Multiple Models in Laravel without overworking the memory

Im trying to figure out the best way to paginate in laravel when i am working with big datasets, the method i am using now is overworking the memory. this is what i am doing: i query from multiple tables, map the results etc, then merge multiple collections, and only after that do i paginate it, i realized though that this is a really bad way of going about this, because i am querying way to much data for no reason, and as the data grows the slower it will become.
the question is what would be the correct way?
i thought maybe i would paginate and then work with the data, the issue is that for instance if i was trying to sort all the merged data by date i wouldn't be getting the proper results because one table may have less data then the other...
here is some of the code to help with clarifying the question
first i will query two tables orders table and transactions table
$transactions = Transaction::all();
$orders = Order::all();
then i will send this all to a action to map it all and format it the way i need to with laravel resources
return $history->execute(['transactions' => $transactions, 'orders' => $orders]);
what this action does is simply map all the transactions and return a resource, then it will map all the orders and return resources for them as well, after which it will merge it all and return the result.
then i take all of this and run it through a pagination action which uses the Illuminate\Pagination\LengthAwarePaginator class.
the results are exactly the way i want them its simply a memory overload.
i tried paginating first instead of doing
$transactions = Transaction::all();
$orders = Order::all();
i did
$transactions = Transaction::orderBy('created_at' 'desc' )->paginate($request->PerPage);
$orders = Order::orderBy('created_at' 'desc' )->paginate($request->PerPage);
and then run it through the action that returns resources.
there are a few issues doing this, firstly, i will no longer get back the pagination data so the app won't know the current page or how many records there are, secondly, if for example the orders table has 2 records, and the transactions table has 10 records, event though the dates of the orders table is after those of the transactions table they will still get queried first.
Use chunk method or paginate
Read documentation.

make the display order based on another table value

I have two tables request and status_tracker. I want to list the row in top which has only one entry in status tracker.
I have the query in $user=DB::table('request')->select('request.*)->get();
I want to add the order based on status_tracker table. If request_id has count '2' in status_tracker table I want to display in top of the table
$user=DB::table('request')->select('request.*)(order may happened here)->get();
if ID 19,11,15 has 2 count in status_tracker it should display first and rest of them will display below as 19,11,15,18,17,16,14,13,12,10.
Is it possible by order the row based on another table field count in laravel?
You could use 'withCount' which will add a column named {relation}_count and orderBy with that, so try something like this:.
$user = App\Request::withCount('status_tracker')
->orderBy('status_tracker_count', 'desc')
->get();
You can read more about this on official Laravel docs
Note: Your model relationship should be well established in order for this to work, so make sure you have specified the relations between both tables :D

Laravel not returning join query to blade

I have two queries, one is lighter on data by using the pivot table as a filter to get data from the main table (student in this case).
$students=\DB::table('student')->join('school_student', 'student.id', '=','school_student.student_id')->get();
This returns a query result from the controller. But will not load into the blade:
$this->layout->content=\View::make('admin.students.index')->with('student', $students);
Whereas this versions returns a similar more data heavy (i.e. outputs all school data each time)
but works in blade.
$students = \Student::with(array('schools' => function($query){$query->where('school_id', '=', 1);}))->get();
Is it simply that DB and view are incompatible?
If so what is the Laravel 4 method to query one table and it's pivot only.
Any help appreciated.
In the blade
#if($student->count())
The first example produces this error:
Call to a member function count() on a non-object
DB::...->get() returns an array, so you can't call ->count() on it (hence "non-object"), but instead you need count($students).
The reason ->count() works when you do the 'more data heavy' method is that you're using Eloquent and it returns Eloquent Collections.
So, basically, you're doing two different things and expecting to treat them the same.
Also, while I'm here I should point out that I think your Eloquent query isn't quite right. First off you're hardcoding the id as 1 (whereas in the DB-style query you don't care about the school ID, and you just use it to join to the pivot table - maybe you used an incomplete query), but also you're using with but you should probably look at has. with eager-loads models, but has is what you want if you just want to check for a condition on a join table.

Resources