I am new to Laravel and building a small Laravel 5.3 app offering free content files as well as files for purchase.
I want users to automatically have access to the free files (content which may be added periodically).
I have a products, purchases (pivot) and users table.
When a user is logged in, how can I query the products table like the following: select all free products (price=0) or join on purchases where users.user_id = purchases.user_id and products.id = purchases.product_id?
Any ideas, or is there a better way to accomplish the same thing?
Thanks
How about if you use following query:
$purchasedProducts = DB::table('purchases')
->join('products', 'products.id', '=', 'purchases.product_id')
->select('purchases.*', 'products.*')
->where([
['purchases.user_id', '=', $loggedinUserId],
['products.price', '=', 0],
])
->get();
If you have defined the relations between user and product then you can query it using orWhereHas as:
Product::where('price', 0)
->orWhereHas('users', function ($q) user($user) {
$q->where('user_id', $user->id);
})
->get();
Assuming your relation name is users.
Related
Explaining my problem, I have two tables in my database called order and order_details.
On my dashboard, I display the three best-selling items (currently work!). However, I would like to display only the best selling items THAT have the status = delivered.
Today, it works like this:
$top_sell_items = OrderDetails::with(['product'])
->select('product_id', DB::raw('SUM(quantity) as count'))
->groupBy('product_id')
->orderBy("count", 'desc')
->take(3)
->get();
The problem is that the order status is stored in another table, called orders, column order_status.
How can I create this rule and include it in my $top_sell_items?
if you relationship is done between this table already, you can use this code, if not you have to go to the OrderDetails Model and add new method orders
$top_sell_items = OrderDetails::with(['product', 'orders'])
->whereHas('orders', function($query) {
$query->where('status', 'delivered');
})
->select('product_id', DB::raw('SUM(quantity) as count'))
->groupBy('product_id')
->orderBy('count', 'desc')
->take(3)
->get();
You could either define a relationship between Orders and OrderDetails or use a join like so...
<?php
$top_sell_items = OrderDetails::with(['product'])
->join('orders', 'orders.id', '=', 'order_details.order_id')
->select('product_id', DB::raw('SUM(quantity) as count'))
->where('orders.order_status', 'delivered');
->groupBy('product_id')
->orderBy("count", 'desc')
->take(3)
->get();
More info here: https://laravel.com/docs/8.x/queries#joins
Depending if you desire this, the following solution might be the most efficient:
$products = Product
::whereHas('orderDetails.order', function ($query) {
$query->where('orders.order_status', 'delivered');
})
->withSum('orderDetails', 'quantity')
->orderBy('order_details_sum_quantity', 'desc')
->take(3)
->get();
It will directly return instances of Product. In addition it puts everything in a single query instead of the two that with produces.
I am a novice in Laravel.
I want to add a filter join through Laravel Eloquent model.
I have below relationship
user belongs to city
user has one restaurant
restaurant has many jobs
Now I want to fetch all jobs with a filter of city.
I tried couple of ways, but ended up in error, like:
$jobs = Job::where("date_time", ">=", $currentDate)->where("city.id", 50)->whereIn('job_status', ['upcoming', 'active'])->orderBy('start_date_time', 'desc')->get();
and the below one
$jobs = Job::with(['restaurant'])->where("date_time", ">=", $currentDate)->where("city.id", 50)->whereIn('job_status', ['upcoming', 'active'])->orderBy('start_date_time', 'desc')->get();
So, here how can I add join from job -> restaurant -> user -> city?
Thanks
Assuming you have city_id in your table
$jobs = DB::table('jobs')->with('restaurant')
->join('users', 'users.id', '=', 'restaurant.user_id')
->join('cities', 'users.id', '=', 'cities.user_id')
->where("table_name.date_time", ">=", $currentDate)
->where("cities.id", 50)
->whereIn('job_status', ['upcoming', 'active'])
->orderBy('table_name.start_date_time', 'desc')->get();
I have edited my answer hope it helps. If not please post your errors and table structure.
You can read about joins here: https://laravel.com/docs/6.x/queries#joins
I'm having a problem with my Search functionnality on my website, I have 2 tables: user and review , In my review table, the owner column is equal to the username column in user table, I want to be able to return in the same result the username of the user table and just below the number of review which I can get with:
Review::where('owner', '=', xxx)->where('invitation_id', '')->count();
The xxx should be equal to the username in the user table
And I have to do this to get the username:
User::where('username', '=', xxx)->first();
What I would like to do (I know this is wrong):
$result = User::where('email','LIKE','%'.$search_key.'%')
->orWhere('username','LIKE','%'.$search_key.'%')
AND
Review::where('username', '=', *$result->username* )
->get();
And I would like to be able to return the search result like this in my result.blade.php:
<h3>Username: {{ user->username }}</h3>
<h3>Username: {{ review->number_review }}</h3>
I checked on the Laravel docs to make a relationship between these 2 tables but can't figure it out, I hope what I said is understandable.
You can use eloquent relationship.
// app/Review.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
public function users()
{
return $this->hasOne('App\User', 'owner', 'username');
}
}
I do not suggest two table relation with username/owner. I suggest to you relation with user primary_id
You can get user info with following code;
Review::where('owner', '=', xxx)->where('invitation_id', '')->with('users')->count();
It getting user info with ->with('users') condition in Review model.
You achieve the required matching criteria by using join and parameter grouping clause
$result = DB::table('users as u')
->join('review as r', 'u.username', '=', 'r.owner')
->where('email','LIKE','%'.$search_key.'%')
->orWhere(function ($query) {
$query->where('u.username','LIKE','%'.$search_key.'%')
->where('r.owner','LIKE','%'.$search_key.'%');
})
->get();
Which will produce where clause as
WHERE u.email LIKE '%somevalue%' OR (r.owner LIKE '%somevalue%' AND u.username LIKE '%somevalue%')
For review count
$result = DB::table('users as u')
->select('u.*',DB::raw("COUNT(*) as review_count"))
->join('review as r', 'u.username', '=', 'r.owner')
->where('u.email','LIKE','%'.$search_key.'%')
->orWhere(function ($query) {
$query->where('u.username','LIKE','%'.$search_key.'%')
->where('r.owner','LIKE','%'.$search_key.'%');
})
->groupBy('u.username')
->get();
You will need to join your user table to the review table.
Something along these lines, might need tweaking.
$result = User::query()
->join('review', 'owner', 'username')
->where('email','LIKE','%'.$search_key.'%')
->orWhere('username','LIKE','%'.$search_key.'%')
->orWhere('username', $result->username)
->orWhere('owner', $result->username)
->get();
In my app I have posts. I wish to show all the posts on the homepage, but order them higher if the post's user has uploaded an image. I can determine if the post's user has uploaded an image by checking if the user has a relationship with a row in the images table, like this:
$post->user->image
My code currently looks like this:
$posts = Post::where('subject_id', '=', $subject->id)
->approved()
->orderBy('created_at', 'desc')
->paginate(18);
Currently, I am simply ordering it by created at, but ideally all posts whose related user has an image will come first, then the rest. I've been looking for a way to do this efficiently and in a way that doesn't just work on the first page.
How should I go about this?
Try this:
$posts = Post::where('subject_id', '=', $subject->id)
->approved()
->select(['*', DB::raw('(SELECT count(images.id) FROM images INNER JOIN users ON users.image_id = images.id WHERE posts.user_id = users.id) as count_images'])
->orderBy('count_images', 'desc')
->orderBy('created_at', 'desc')
->paginate(18);
Try this:
$posts = Post::where('subject_id', '=', $subject->id)
->approved()
->with('user')
->join('users', 'users.id', '=', 'post.user_id')
->select(['post.*', 'users.avatar'])
->orderBy('image', 'desc')
->orderBy('created_at', 'desc') // ->latest() can be used for readability
->paginate(18);
This code eager loads users to reduce number of DB queries and doesn't use raw queries which should be avoided, because mistake can make your application vulnerable to SQL injection.
Explanation:
We eager load relationship using ->with('user') method, then join users table, select all fields from posts table and only image field from users table, then order results by image and paginate results.
Result should look like this:
App\Post:
id
title
...
image(from users table)
App\User (eager loaded relationship)
id
name
email
...
image
created_at
I am attempting to do the equivalent of this:
select p.id, p.title, b.brand,
(select big from images where images.product_id = p.id order by id asc limit 1) as image
from products p
inner join brands b on b.id = p.brand_id
Here is where I am at now, but it of course doesn't work:
public function getProducts($brand)
{
// the fields we want back
$fields = array('p.id', 'p.title', 'p.msrp', 'b.brand', 'p.image');
// if logged in add more fields
if(Auth::check())
{
array_push($fields, 'p.price_dealer');
}
$products = DB::table('products as p')
->join('brands as b', 'b.id', '=', 'p.brand_id')
->select(DB::raw('(select big from images i order by id asc limit 1) AS image'), 'i.id', '=', 'p.id')
->where('b.active', '=', 1)
->where('p.display', '=', 1)
->where('b.brand', '=', $brand)
->select($fields)
->get();
return Response::json(array('products' => $products));
}
I don't really see anything in the docs on how to do this, and I can't seem to piece it together from other posts.
In "regular" SQL, the subquery is treated AS a column, but I am not sure how to string that together here. Thanks for any help on this.
I strongly recommend you to use Eloquent, instead of pure SQL. It's one of the most beautful things in Laravel. Two models and relations and it's done! If you need to use pure SQL like that, put it all in DB::raw. It's easier, simpler and (ironically) less messy!
With the models, you could use relations between the two tables (represented by the models itself) and say (so far I understood) that Brands belongs to Products, and Images belongs to Product. Take a look at Eloquent's documentation on Laravel. Probably will be more clearly.
Once the relations are done, you can only say that you wanna get
$product = Product::where(function ($query) use ($brand){
$brand_id = Brand::where('brand', '=', $brand)->first()->id;
$query->where('brand_id', '=', $brand_id);
})
->image()
->get();
That and a better look at Eloquent's documentation should help you to do the job.
P.S.: I didn't test the code before send it and wrote it by head, but i think it works.