Fetching has many relationship data Laravel and using avg function - php

I am using Laravel 5 with vue js. Basically i am fetching data using axios and trying to display on the webpage using vue js v-for directive.
i have tables in database like this:
ratings Table
id review_id rating
Then i have a
reviews table
id review
They have one to many relationship between. so here in my Review Model i have method
public function ratings()
{
return $this->hasMany('App\Rating')
->selectRaw('review_id,AVG(rating) AS average_rating')
->groupBy('review_id');
}
so here i want to fetch list of reviews with their average ratings. so in my controller i am doing this:
public function getAllReviews(Request $request)
{
$reviews = Review::with('ratings')->get();
return $reviews;
}
So i am getting result but the problem is every review doesnt have ratings record so it is returning null? maybe...
when i try to render in vue template it throws an error undefined because in our collection some reviews do not have ratings.
Now my question is: Can i do something like if there is no record in the ratings for a particular review is it possible to add an array with value 0?? so in my frontend it wont see as undefined.
I hope i am successful to explain i am trying.
Thank you.

You may do it this way:
public function getAllReviews(Request $request)
{
$reviews = Review::selectRaw('*, IFNULL((SELECT AVG(rating) FROM ratings where ratings.review_id = reviews.id), 0) as avg_rating')->get();
return $reviews;
}

I would suggest using the basic relationship and a modified withCount():
public function ratings() {
return $this->hasMany('App\Rating');
}
$reviews = Review::withCount(['ratings as average_rating' => function($query) {
$query->select(DB::raw('coalesce(avg(rating),0)'));
}])->get();

public function showProduct($id)
{
$data = Product::where('category_id',$id)
->selectRaw('*, IFNULL((SELECT AVG(value) FROM ratings where ratings.product_id = products.id), 0) as avg_rating')
->get();
return view('ecommerce.web.productsOfcategory',compact('data'));
}

$avgQuery = "IFNULL((SELECT AVG(ratings.rating) FROM ratings WHERE ratings.review_id = reviews.id),'No Ratings') as avg_rating";
$reviews = Review::query()->selectRaw("reviews.*, $avgQuery")->get();
//SQL Query
$sqlQuery = "select reviews.*, IFNULL((SELECT AVG(ratings.rating) FROM ratings where ratings.review_id= ratings.id), 'No ratings') as avg_rating FROM reviews";

Related

How to retrieve data from one table based on the calculation of another two table?

Suppose I have Three model named as Customer ,Invoice and Payment.
Invoice and Payment model looks like
id , customer_id, amount
I want to get only those customer whose
Invoice.sum(amount)>Payment.sum(amount) with these amount difference
I am currently retrieve like
$customers=Customer::get();
foreach($customers as $customer)
{
$pay=Payment::where('customer_id',$customer->id)->sum('amount');
$due=Invoice::where('customer_id',$customer->id)->sum('amount');
if($due>$pay){
// showing this customers
}
}
Is there any better way with eloquent join?
How Can I get In laravel eloquent ?
Have you set any relationship in the Model? A better eloquent query will look like this. You might need to adjust a bit
Customer::join('payment','customer.id','=','payment.customer_id')
->join('invoice','customer.id','=','invoice.customer_id')
->select(array('customer.*'),DB::raw("SUM(payment.amount) as payment_sum,SUM(invoice.amount) as invoice_sum"))
//->where('customer_id',$customer->id)
->groupBy('customer.id') //replace with anything that make sense for you.
->havingRaw('invoice_sum > payment_sum')
->get();
Try this
First, define the relationship in your Customer Model
public function payments()
{
return $this->hasMany(Payment::class); //based on your logic or structure
}
public function invoices()
{
return $this->hasMany(Invoice::class); //based on your logic or structure
}
Customer::with(['payments' => function($query) {
$query->sum('amount');
}])
->get();
or
$customers=Customer::with('payments','invoices')->get();
foreach($customers as $customer)
{
$pay = $customer->payments()->sum('amount');
$due = $customer->invoices()->sum('amount');
//other logic
}

Retrieving data with Array values - laravel

My task is to display all contacts for selected groups. When i select two gorups like facebook and instagram, i have to display all contacts belonging to both group.
When i select multiple groups like below and do return $explode_groups, i get the id's of both groups like 1,2.
But my issue is, when i am displaying the contact as return $selected_contacts i get only contacts for group 1.
Why is this happening?
Group
public function customers()
{
return $this->belongsToMany('App\Customer','customer_group','group_id','customer_id')
->withTimestamps();
}
Customer
public function groups()
{
return $this->belongsToMany('App\Group','customer_group','customer_id','group_id')
->withTimestamps();
}
Controller
$get_selected_groups = $request->get('group');
$explode_groups = implode(', ', $get_selected_groups);
$selected_groups = Group::where('id',$explode_groups)->first();
$selected_contacts = $selected_groups->customers()->get();
response
{"id":2,"title":"test","no_of_contacts":0,"user_id":1,"created_at":"2018-04-15 23:55:30","updated_at":"2018-04-15 23:55:30","customers":[{"id":1,"name":"Benson Jones Thomson","phone":"0247878234","group_id":null,"user_id":1,"created_at":"2018-04-16 00:14:20","updated_at":"2018-04-16 05:31:05","pivot":{"group_id":2,"customer_id":1,"created_at":"2018-04-16 05:33:08","updated_at":"2018-04-16 05:33:08"}},{"id":2,"name":"Lawrence Pitcher","phone":"0244371112","group_id":null,"user_id":1,"created_at":"2018-04-16 07:59:15","updated_at":"2018-04-16 07:59:15","pivot":{"group_id":2,"customer_id":2,"created_at":"2018-04-16 07:59:15","updated_at":"2018-04-16 07:59:15"}}]}
You should be using whereIn() to select multiple ids from the given array and to load the relation of each model use with() method.
Like:
$get_selected_groups = $request->get('group');
return Group::whereIn('id', $get_selected_groups)->with('customers')->get();
Try this
$selected_contacts = Customer::whereHas('groups', function($q) use ($explode_groups){
$q->whereIn('id', $explode_groups);
})->get();
You should try this
$selected_groups = Group::whereIn('id',$get_selected_groups)->get();
$selected_contacts = array();
foreach($selected_groups as $selected_group){
$selected_contacts[] = $selected_group->customers()->get();
}

How to join table with req->id

public function getTourDetail(Request $req)
{
//Get link detail
$tour = Tour::where('id',$req->id)->first();
//I want to take location.city of the location table
$detail = Tour::join('location','tour.id_location','=','location.id')
->whereColumn([
['tour.id_location','=','location.id']
])
->get(array(
'tour.id as id_tour',
'location.image',
'tour.name',
'tour.id_location',
'location.city'
));
return view('page.tour-detail',compact('tour','detail'));
}
I would like to be able to combine two query statements to get information from the location table ($ detail) like the id of the link request ($ tour).
Since you use models, you can use Eloquent relationships to load related data. First, define a relationship in the Tour model:
public function location()
{
return $this->belongsTo(Location::class, 'id_location')
}
Then load Tour and get related location:
$tour = Tour::find($req->id);
$relatedLocation = $tour->location;
First thing, if you are using model then using eloquent relationship will be a better idea to deal with the situation like yours. But if you want to join your table then this will be the way:
public function getTourDetail($id)
{
$tour = Tour::where('id',$id)->first();
//I want to take location.city of the location table
$detail = DB::table('location')
->join('tour','tour.id_location','=','location.id')
->select(
'tour.id as id_tour',
'location.image',
'tour.name',
'tour.id_location',
'location.city'
)->get();
return view('page.tour-detail',compact('tour','detail'));
}
Note: if you are getting id from submitted form then replace first portion of the code with:-
public function getTourDetail(Request $request)
{
$tour = Tour::where('id',$request->id)->first();

Laravel Eloquent - Using array in find() method

I have three tables - users, products and orders
There is a relation between users and orders (users has many orders).
orders table contains product_id and user_id column.
Now I want to access the product details of orders for a user.
What I am trying:
public function myOrders(){
$orders = Auth::user()->orders->pluck('product_id');
$products = Product::find($orders);
return view('shop.myorders', compact('products'));
}
But this is not working. Can anyone help me? What other way can be better to achieve this?
As mentioned, find() will always return 1 item, and expects a string/int for the parameter. You want to use where and get instead. With an array of ids, you can use whereIn.
public function myOrders(){
$orders = Auth::user()->orders->pluck('product_id');
$products = Product::whereIn('id', $orders)->get();
return view('shop.myorders', compact('products'));
}
I assume you have orders() relation defined in the Product model:
public function orders()
{
return $this->hasMany(Order::class)
}
Then you'll be able to load products from all user's orders:
$products = Product::whereHas('orders', function($q) {
$q->where('user_id', auth()->id())
})->get();

Performing a sum() on a collection in Laravel

I have an application with a basic forum system where users can "like" a topic multiple times. My models extend Eloquent and I'm trying to get the sum of votes a user has for a specific topic... Basically, I'm trying to accomplish something like:
$votes = Auth::user()
->votes->has('topic_id', '=', $topic->id)
->sum('votes');
However, when executing this, I get the following error...
Call to a member function sum() on a non-object
I've also tried
public function show($forumSlug, $topicSlug)
{
$topic = Topic::whereSlug($topicSlug)->first();
$votes = Topic::whereHas('votes', function ($q) use ($topic)
{
$q->where('topic_id', '=', $topic->id)->sum('votes');
});
dd($votes);
}
However, with that I receive an error stating:
Unknown column 'ideas.id' in 'where clause' (SQL: select sum(votes)
as aggregate from votes where votes.idea_id = ideas.id and
idea_id = 1)`
You may try something like this (Not sure about your relationship but give it a try):
$topic = User::with(array('topics' => function ($query) use ($topic_id) {
// $query = Topic, so it's: Topic::with('votes')
$query->with('votes')->where('topics.id', $topic_id);
}))->find(Auth::user()->id)->topics->first();
// Count of total votes
dd($topic->votes->count());
P/S: If it doesn't work then please post your model's relationship methods.
I managed to get it working, though I'm not sure I like this approach. I'd love to hear if anyone knows of a better way of doing this...
Basically, I used my relationships to filter() the votes and then used sum() on the filtered collection.
public function show($forumSlug, $topicSlug)
{
$userId = is_null(Auth::user()) ? false : Auth::user()->id;
$topic = Topic::whereSlug($topicSlug)->first();
$votes = $topic->votes->filter(function ($votes) use ($userId)
{
return $votes->user_id == $userId;
})->sum('votes');
return View::make('forums.topics.show', compact('topic', 'votes'));
}

Categories