Laravel Eloquent Relationship - not fetching based on condition - php

I wanted to fetch all id & name from User table which satisfies the condition , order_userId of Orders table == id of User table and order & uploadId columns of Orders table has the values false & null respectively. The below code returns all rows if data from User table without checking the where condition i've specified.. How can i fix this?
$data = User::with(['orders'=>function ($query){
$query->where('order', false);
$query->whereNull('uploadId');
}])->pluck('name', 'id');
User Model
public function orders()
{
return $this->belongsTo(Orders::class, 'order_userId', 'id');
}
The above code gives an output as below:
{
"id": 2,
"name": "jen",
"orders": null
},
{
"id": 3,
"name": "jos",
"orders": null
}

Try
$data = User::whereHas('orders', function ($query) {
$query->where('order', false);
$query->whereNull('uploadId');
})->pluck('name', 'id');

try This Solution:
The right relation is that, User has many orders.
User Model:
public function orders()
{
return $this->hasMany(Orders::class, 'order_userId', 'id');
}

Checkout this also..
$data = User::whereHas('orders', function ($query) {
$query->where([['order', false],['uploadId','>',0]]);
})->pluck('name', 'id');

Related

Laravel modal query

I am trying to get array of related model to my data and it returns null.
Code
public function collection()
{
return Product::with(['allBarcodes' => function ($query) {
$query->select('serial_number');
}])->get();
}
result
Also I tried pluck like $query->pluck('serial_number'); and result was
My real data
the data I suppose to receive is like
[{
"id":1,
"product_id":1,
"serial_number":"5245412185", // I only need this to be return as array
"sold":1,
"created_at":"2020-05-24T04:21:56.000000Z",
"updated_at":"2020-05-24T04:21:56.000000Z"
}]
Any idea?
When you are doing this $query->select('serial_number'); you are only selecting serial_number and not the column that connects both the modals i.e. product_id inside barcodes table.
Do this.
$query->select('product_id', 'serial_number');. However this will return 2 columns. If you want just one then you will have to use collection transform.
$products = $products->map(function ($product) {
$product->allBarcodes->transform(function ($q) {
return $q->serial_number;
});
return $product;
});
Keep me posted in the comments below.

Order data by pivot table when try to use With

I have tables Polfzms <- Genes
Polfzm model have next relation
public function gene()
{
return $this->belongsTo('App\Gene');
}
I need get all data from Polfzms table with data from Genes table and order it by name from pivot table (Genes). I try next
$data = Polfzm::with([
'gene' => function ($query) {
$query->orderBy('name', 'asc');
},
])->get();
but it not order data by name. How can I do it?
You could try to set this in the relationship definition:
Polfzm.php
public function gene()
{
return $this->belongsTo('App\Gene')->orderBy('name', 'asc');
}
Then in your controller:
$data = Polfzm::with('gene')->get();
If I understand correctly, you could use a collection sortBy helper for this one.
An example could be:
$data = Polfzm::with('gene')
->get()
->sortBy(function ($polfzm) {
return $polfzm->gene->name;
});

Joining 3 tables and compute average of a column

I am currently learning Laravel and I am using DB class when joining the three tables. I am able to join the three tables but I need to get the average of a certain column for a teacher (ratings table, rating column), here's what I have and I am stuck here.
Here's my table design
And here's my query
$teachers = DB::table('ratings as r')
->join('users as u','r.teacher_id', '=', 'u.id')
->join('user_infos as ui','r.teacher_id', '=', 'ui.user_id')
->select('r.rating','ui.about','ui.first_name','ui.last_name','ui.avatar','ui.rate','u.*')
->where('u.status', 1)->get();
Also, the results for same user is being repeated. The user has two ratings from the ratings table and it appear two times in my view.
What I want to display here is the list of all teachers and in each card, with their corresponding ratings.. so if I have two teachers in the table, it will display the two teachers and on the right top side of the card is their rating.
Here is a possible solution:
$teachers = DB::table('ratings as r')
->join('users as u','r.teacher_id', '=', 'u.id')
->join('user_infos as ui','r.teacher_id', '=', 'ui.user_id')
->select(DB::raw('AVG(r.rating) as average_rating'),'ui.about','ui.first_name','ui.last_name','ui.avatar','ui.rate','u.*')
->groupBy('r.teacher_id')
->where('u.status', 1)->get();
Ok..since you are using Laravel naming convention/recommendation, I think would be easier/cleaner if you use Eloquent.
I'm not sure if you already created the Eloquent models. And, because of that, I'll put everything here (models, etc).
Ratings model
class Rating extends Model
{
protected $guard = ['id'];
public function teacher()
{
return $this->belongsTo(User::class, 'teacher_id');
}
public function student()
{
return $this->belongsTo(User::class, 'student_id');
}
}
User info model
class UserInfo extends Model
{
protected $guard = ['id'];
public function user()
{
return $this->belongsTo(User::class);
}
}
User model
class User extends Model
{
protected $guard = ['id'];
public function ratings()
{
return $this->hasMany(Rating::class, 'teacher_id');
}
public function infos()
{
return $this->hasMany(UserInfo::class);
}
}
Possible query solution for your problem:
$ratings = Rating::with(['teacher.infos', 'student.infos'])->whereHas('teacher', function($q) {
$q->where('status', true);
})->get();
This will probably give you something like this:
// ratings: [
// "id": 1,
// "teacher_id": 1,
// "student_id": 2,
// ....
// "teacher": {
// "id": 1,
// "name": "...."
// ...
// "infos": [{
// "id": 1,
// "skype": '....'
// ....
// }]
// },
// "student": {
// "id": 2,
// "name": ....,
// "infos": [{
// "id": ...
// }]
// }
// ]
Now you have a collection of Ratings. And, if you need to access the user or the user info, you just need to
// Example:
$firstStudentInfo = $ratings->isEmpty() ? null : $ratings->first()->student->infos;
If you need to calculate something, you can either use an extra query (db) or just a single method on your
collection. I think, in this case, a collection can be faster. You can also create a specific collection
for your "Ratings" model, with specific calculations ("RatingsCollection").
Another example (blade template). Since we already loaded everything "eager load", we don't need to worry
with N+1 query problems here. (https://laravel.com/docs/5.5/eloquent-relationships#eager-loading)
// Ratings grouped by teacher
#foreach ($ratings->groupBy('teacher') as $rating)
Teacher: {{ $rating->avg()...}} or whatever..
#endforeach
If you still want to use DB, #Md Mahfuzur Rahman will do the trick.
:)

How OrderBy afterwards HasMany and BelongsTo Relationships

I created a relationship between the "Review, Games and Info" tables, unfortunately, though, the main table is Games, and he orders me all for Games, While I would like to order the ID of "review" table.
Models: Review
public function games()
{
return $this->hasMany('App\Models\Giochi', 'id_gioco', 'id');
}
Models: Giochi
public function review()
{
return $this->belongsTo('App\Models\Review', 'id', 'id_gioco');
}
public function infogiochi()
{
return $this->belongsTo('App\Models\InfoGiochi', 'id', 'id_gioco');
}
Models: InfoGiochi
public function games()
{
return $this->hasMany('App\Models\Giochi', 'id', 'id_gioco');
}
Controller:
$review = Giochi::with('Review','InfoGiochi')->orderBy('id','DESC')->get();
Here is a screenshot of my json:
How do I order content for review table IDs?
You have 2 options. You use a join and order in the sql statement or you order it after retrieving the results in the collection.
Using Join
Giochi::select('giocos.*')
->with('Review','InfoGiochi')
->leftJoin('reviews', 'reviews.id', '=', 'giocos.id_gioco')
->orderBy('reviews.id','DESC')
->get();
Sorting Collection
Giochi::with('Review','InfoGiochi')
->get()
->sortByDesc(function($giochi) {
return $giochi->review->id;
});
This would be the shortest version to sort on the collection:
Giochi::with('review')
->get()
->sortByDesc('review.id');
You can modify your relationship query when you fire it:
Giochi::with([
'Review' => function ($query) { return $query->orderBy('id','DESC'); },
'InfoGiochi'
])->orderBy('id','DESC');
You can try with a raw query or you can use ->orderBy() directly on review function.

Laravel leftJoin not return correctly

I have a problem with laravel select using leftJoin. I'm trying to select 2 posts and count how many comments there is(first post have 7 comments, second - 0), but I got only first post with 7 comments.
Code is:
$posts = DB::table('posts')
->leftJoin('comments', 'comments.post', '=', 'posts.id')
->select(DB::raw('posts.title, posts.body, posts.created_at, posts.slug, CASE WHEN comments.post IS NULL THEN 0 WHEN comments.post IS NOT NULL THEN count(comments.post) END as count'))
->get();
And when I trying to check what i see in web browser i got error:
Call to a member function count() on a non-object
This error in my view file at line where i using #if($posts->count())
I have debugged that i got only one post from using print_r().
Any suggestions?
I think your best bet here is to use some of the built in functionality of laravel's Eloquent ORM.
set up a relationship in the models:
Post.php:
<?php
class Post extends Eloquent {
protected $table = 'posts';
public function comments()
{
return $this->hasMany('Comment', 'posts');//first param refrences the other model, second is the foreign key
}
Comment.php:
<?php
class Comment extends Eloquent {
protected $table = 'comments';
public function comments()
{
return $this->belongsTo('Post');//first param refrences the other model, second is unnecessary if you are using auto incrementing id
}
now you have a relationship set up and there is no need for the join.
Usage:
there may be a better way to do this, but this should work.
$posts = Post::with('comments')->get();//retrieves all posts with comments
foreach($posts as $post){
$count = count($post['comments']);
$post['comment_count'] = $count;
}
return $posts;
this will return a result that contains all of the posts, with a field called 'comments' that contains an array of all of the comments related. the 'comment_count' field will contain the count.
example:
[
{
"id": 1,
"created_at": "2014-07-02 11:34:00",
"updated_at": "2014-07-02 11:34:00",
"post_title": "hello there",
"comment_count": 1,
"comments": [
{
"id":'blah'
"comment_title":"blah"
}
]
}
you can now pass this to your view and loop through each post and get the $post['comment_count']

Categories