Eloquent OrderBy and Take not working in a hasMany relationship - php

I am trying to limit the number of entries returned in a hasMany relationship which works fine when either orderBy or take is used. However when they are used together, the results appear to be wrong.
What is wrong with this query?
Expected Results = 2 rows of data
Actual results = 2 rows of data
public function manual_ticket_log(){
return $this->hasMany('App\ManualTicketLog','manual_ticket_id','id')->orderBy('id','desc');
}
Expected Results = 1 row of data
Actual Results = 1 row of data
public function manual_ticket_log(){
return $this->hasMany('App\ManualTicketLog','manual_ticket_id','id')->take(1);
}
--ERROR HERE--
Expected Results = 1 row of data
Actual results = Empty array is returned
public function manual_ticket_log(){
return $this->hasMany('App\ManualTicketLog','manual_ticket_id','id')->orderBy('id','desc')->take(1);
}

intead of hasMany you can use HasOne to get only one record:
public function manual_ticket_log(){
return $this->hasOne('App\ManualTicketLog','manual_ticket_id','id')->orderBy('id','desc');
}
hasOne will get the first result only.

Related

How to select only one Column with scope of eloquent model?

I got two tables. Both have a relationship to each other. I´m trying to query both to get the matching results. This results get checked if they also have an column which matches with a parameter value.
I´m trying it with a scope and it work. I only need one column from the second table and I´m trying to use it as column in my first table when I got my result.
So the code works and I got an result but I´m trying to filter to select only one column from the second table.
My code look like that.
My controller:
public function test()
{
$UID='LQuupgYvnuVzbEoguY4TF8bnHUU2';
$event=Events::withState($UID)->get();
echo $event;
}
My model scope function:
public function scopeWithState($query,$UID){
return $query->with(['EventLiked' => function($query) use($UID) {
$query
->where('EventLiked.UID', $UID)
;
}]);
}
My hasMany relationship function:
public function EventLiked()
{
return $this->hasMany(EventLiked::class,'EID','ID')->select('State','UID','EID');
}
I would go for specifying columns inside closure.
New scope:
public function scopeWithState($query,$UID){
return $query->with(['EventLiked' => function($query) use($UID) {
$query
->where('EventLiked.UID', $UID)
->select('State');
}]);
}
Calling scope:
$event=Events::withState($UID)->get();
You're not getting expected results because Laravel splits it into 2 queries:
First, for selecting events.
Then it plucks EID
Second, when it looks for EventLiked where matching ID's is found (from second step) and loads as relationships.
So you want to change select statement only in 2nd query. Not in a first one

Laravel Get All Rows From Different Ids

today i was just practicing my skills and got stuck. I just want to fetch data from the database using specific ids which i put inside my session as an array. The problem is, i cant find a way to fetch all the data that includes these ids.
here's my cart checkout method
public function checkout(){
$uniqid = session('products');
$post=Post::find($uniqid);
return view('pages.checkout')->with('post',$post);
}
I am getting no data, even if i try to get something i only get one field when there's something like 7 of them.
Here's the session products array
0 "15be4aa3b55f10"
1 "15be4814ceb2a0"
2 "15be4814ceb2a0"
3 "15be4aa3b55f10"
4 "15be4aa3b55f10"
5 "15be4aa3b55f10"
6 "15be4aa3b55f10"
7 "15be4aa3b55f10"
The find query returns single row of data. If you want to fetch more than 1 data, use the all query:
$post = Post::all();
or if you want to get all data with the same id as your $uniqid, use the where query:
$post = Post::where('column_name', $uniqid)->get();
EDIT
IF your session has many id, you may want to loop and find all the data with the same id as your $uniqid
public function checkout(){
$products = [];
foreach(session('products') as $session){
$post=Post::find($session->id);
$products[] = $post;
}
return view('pages.checkout')->with('products ',$products);
}
you may try this:
public function checkout(){
$uniqid = session('products');
$products = Post::whereIn('unique_id', $uniqid)->get();
return view('pages.checkout')->with('products',$products);
}
where whereIn method takes a field name and array of values
From laravel docs:
The whereIn method verifies that a given column's value is contained within the given array
You should use whereIn() method to fetch records against multiple ids. do like this
public function checkout(){
$uniqidsArray= session('products');
$post=DB::table('yourTableName')
->whereIn('id', $uniqIdsArray)
->get();
return view('pages.checkout')->with('post',$post);
}

orderBy in hasOne relation doesn't work

I have a table (weathers) with several thousands rows, 90000 +- at the moment, each one belonging to one location.
This table can have multiple rows belonging to one location, but I still want just one, the last one for a given location.
My model Location have this relation defined as:
...
public function last_weather() {
return $this->hasOne(\App\Weather::class, 'id_location')->orderBy('weathers.id', 'DESC');
}
...
And on my controller I'm retrieving the last_weather like:
...
Location::with(['last_weather'])->findOrfail(1);
...
The strange thing is that this worked until I have 45000+- rows in the weather table, I have 3200 locations, and the last records for each location that are returned are on 40000+- rows (between id 40000 and 43000 +-, of the weathers table)
I have checked my DB and I have each location updated on the 80000's, but the relation are returning the data from the 40000's. This is not even the first or the last weather for each location.
You can do this in your Location model
public function weathers()
{
return $this->hasMany(\App\Weather::class, 'id_location');
}
public function lastWeather()
{
return $this->weathers()->latest()->first();
}
Then in your controller
$location = Location::findOrfail(1);
then you can access the last weather like this
$location->lastWeather();
UPDATE
Or you can adjust how you eager load weathers
$location = Location::with([
'weathers' => function($query) {
$query->orderBy('id', 'DESC')->first();
},
])
->findOrfail(1);
Order by will return all rows, to only return a single row for each matching condition you need to use Group by
I never used Laravel, but looking at your code I'm guessing your query should look like this:
return $this->hasOne(\App\Weather::class, 'id_location')->groupBy('weathers.id', 'DESC');

Cannot retrieve single column from database. Laravel

I'm trying to retrieve single column from my table grades.
For that I have used following code in my controller:
public function verify($id,$sid)
{
$grade=Grade::all('annual')->whereLoose('id',$id);
return $grade;
}
Where, annual is column name. But it is returning empty set of array [].
all() takes a list of columns to load from the database. In your case, you're fetching only one column called annual, therefore filtering on id later on does not return results. Replace your code with the following and it should work:
$grade = Grade::all('id', 'annual')->whereLoose('id', $id);
Keep in mind that it will return a collection of objects, not a single object.
NOTE: you're always loading all Grade objects from the database which is not efficient and not necessary. You can simply fetch object with given id with the following code:
$grade = Grade::find($id); // fetch all columns
$grade = Grade::find($id, ['id', 'annual']); // fetch only selected columns
The code you are using is loading all rows from the grades table and filtering them in code. It is better to let your query do the filter work.
For the columns part, you can add the columns you need to the first() function of the query, like so:
public function verify($id,$sid)
{
$grade = Grade::where('id', $id)->first(['annual']);
return $grade->annual;
}

Eloquent HasMany relationship, with limited record count

I want to limit related records from
$categories = Category::with('exams')->get();
this will get me exams from all categories but what i would like is to get 5 exams from one category and for each category.
Category Model
public function Exams() {
return $this->hasMany('Exam');
}
Exam Model
public function category () {
return $this->belongsTo('Category');
}
I have tried couple of things but couldnt get it to work
First what i found is something like this
$categories = Category::with(['exams' => function($exams){
$exams->limit(5);
}])->get();
But the problem with this is it will only get me 5 records from all categories. Also i have tried to add limit to Category model
public function Exams() {
return $this->hasMany('Exam')->limit(5);
}
But this doesnt do anything and returns as tough it didnt have limit 5.
So is there a way i could do this with Eloquent or should i simply load everything (would like to pass on that) and use break with foreach?
There is no way to do this using Eloquent's eager loading. The options you have are:
Fetch categories with all examps and take only 5 exams for each of them:
$categories = Category::with('exams')->get()->map(function($category) {
$category->exams = $category->exams->take(5);
return $category;
});
It should be ok, as long as you do not have too much exam data in your database - "too much" will vary between projects, just best try and see if it's fast enough for you.
Fetch only categories and then fetch 5 exams for each of them with $category->exams. This will result in more queries being executed - one additional query per fetched category.
I just insert small logic inside it which is working for me.
$categories = Category::with('exams');
Step 1: I count the records which are coming in response
$totalRecordCount = $categories->count()
Step 2: Pass total count inside the with function
$categories->with([
'exams' => function($query) use($totalRecordCount){
$query->take(5*$totalRecordCount);
}
])
Step 3: Now you can retrieve the result as per requirement
$categories->get();

Categories