filter by first foreign key - laravel

I am creating a website to compare product prices in different stores. I have set up a database with these two tables.
+---------+ +------------+
| Product | | Price |
+---------+ +------------+
| id | | id |
| name | | product_id |
+---------+ | price |
| date |
+------------+
Now I would like to be able to get all the products where the last price.date is earlier than a certain date.
I have tried using the following code, but without success.
Product::with(['prices' => function($q){
$q->first()->where('date', '<', Carbon::yesterday());
}])->get()->prices();
Can someone help me with this problem?
Thanks in advance :)

With() is only for eager loading records.
You need to use whereHas:
Product::whereHas('price',function($q) {
return $q->where('date', '<', Carbon::yesterday());
})->whereHas('price',function($q) {
return $q->where('date','>=',Carbon::yesterday());
},'=',0)->get();
This will return all products where it has prices whose date is less than Carbon::yesterday()
Official Documentation

Related

How can I fetch value from 3 tables using laravel relationship?

I have 4 tables named: categories, products, blogs, companies.
+-----------+
| Category |
+----+------+
| id | name |
+----+------+
| 1 | Cat1 |
| 2 | Cat2 |
+----+------+
+-----------+
| Company |
+----+------+
| id | name |
+----+------+
| | |
+----+------+
+-------------------------+
| Product |
+----+-------------+------+
| id | category_id | name |
+----+-------------+------+
| 1 | 1 | P1 |
| 2 | 2 | P2 |
| 3 | 1 | P3 |
+----+-------------+------+
+---------------------------+
| Blog |
+----+------------+---------+
| id | product_id | heading |
+----+------------+---------+
| 1 | 1 | H1 |
| 2 | 2 | H3 |
| 3 | 3 | H4 |
+----+------------+---------+
Blog Model
public function product()
{
return $this->belongsTo(Product::class);
}
Product Model
public function company()
{
return $this->belongsTo(Company::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
Blog::with('product.category')
->where('status', 'Y')
->where('featured_position', 'Y')
->orderBy('id', 'DESC')
->get();
From the above tables the result will show 2 blogs namely blogs having id 1 and 3. But the above code is fetching result for all the blogs from the blog table.
You'll want to use a whereHas to query the relationship.
$categoryId = 1;
$productQuery = function ($query) use ($categoryId) {
// This $query object will be for the Product models, so we can treat it as
// such.
// We can query like we would on a Product, like Product::where([...]).
$query->with('category')->where('category_id', $categoryId);
};
$blogs = Blog::whereHas('product', $productQuery)
->with(['product' => $productQuery])
->get();
I've set the category ID to a variable, in case you need to change it during runtime.
Also, note that the with is completely optional.
If you exclude it, your query will run exactly the same, just without constrained eager loading. The effects of this are just that you will have to perform more database requests. The benefits come if you never actually need the relationship, then it won't have been fetch unnecessarily.
If you're curious what the SQL command will be, it will be:
SELECT * FROM `blogs`
WHERE EXISTS (
SELECT * FROM `products`
WHERE `blogs`.`product_id` = `products`.`id` AND `category_id` = ?
)
In simple terms, it will select everything from the blogs table.
It's then going to query the products table, using an inner join, to select products that have a corresponding blog entry.
The second part of the where clause is going to just get the specific character. The ? is because category_id can be any integer.
Catory with id 1
fetch its products
fetch blogs for each of its products ( map over products )
flatten the results ( since its gonna be nested for each product )
Category::find(1)->products->map->blogs->flatten();
you can use Tinker to interact with you application's query builder and eloquent models from terminal you can use :
$ php artisan tinker
For more clause you can use collection methods :
Category::find(1)->products->map->blogs->flatten()->where('status', 'Y')
->where('featured_position', 'Y')
->sortDesc('id') ;

Use data gotten from one table to get data from another data

I have three tables
Job Model
+---------------------------+
| id | name |
+---------------------------+
| 1 | web design |
+---------------------------+
| 2 | desktop development |
+---------------------------+
Applicant Model
+----------------------------------------------------------+
| id | job_id | user_id | desc |
+----------------------------------------------------------+
| 1 | 2 | 1 | I am an expert developer |
+----------------------------------------------------------+
| 2 | 2 | 2 | I am good |
+----------------------------------------------------------+
User Model
+----------------+
| id | name |
+----------------+
| 1 | john |
+----------------+
| 2 | steve |
+----------------+
Using eloquent laravel,
How do I get applicants with job_id "2" and their user name together.
Tried a lot but unfortunately to no avail.
You would use a query something like this:
$jobs = Job::where('id', 2)
->join('applicants', 'jobs.id', '=', 'applicants.job_id')
->join('users', 'applicants.user_id', '=', 'users.id')
->select(['user.name', 'job.name', 'applicant.desc'])
->get();
You will have to change it to your requirements but should about what you need.
You can get more info here:
https://laravel.com/docs/5.7/queries
Hope that helps

Laravel. How to get relationships where foreign key is an array

I am trying to retrieve database rows with their relationships. However, the local key is an array. Let me explain using an example.
Lets say I have a table of countries and a table of pages. Each country can have many pages. Each page can belong to multiple countries. I do not have the flexibility to change this schema.
pages
+-------------+-----------+
| id | name | countries |
+-------------+-----------+
| 1 | Page 1 | 1 |
+-------------+-----------+
| 2 | Page 2 | 1,2,3 |
+-------------+-----------+
| 3 | Page 3 | 4,5,6 |
+-------------+-----------+
countries
+----+----------------+
| id | name |
+----+----------------+
| 1 | United States |
+----+----------------+
| 2 | United Kingdom |
+----+----------------+
| 3 | Germany |
+----+----------------+
| 4 | France |
+----+----------------+
| 5 | Hong Kong |
+----+----------------+
| 6 | Thailand |
+----+----------------+
| 7 | Belgium |
+----+----------------+
| 8 | Singapore |
+----+----------------+
My model and controller look something like:
country
public function pages()
{
return $this->hasMany(Page::class, 'id', 'countries');
}
MemberController.php
$countries = Country::with('pages')->get();
This is returning all countries, but only Page 1 contains any relationships.
Is there a way to retrieve relationships using a whereIn approach so all three countries will return appropriate pages?
Thanks in advance
Since Page can belong to many Countries, you need to create a pivot table called country_page and remove the countries column.
Then define two belongsToMany() relationships in both models:
public function pages()
{
return $this->belongsToMany(Page::class);
}
If you're not following Laravel naming conventions listed in my repo and you gave the pivot name a custom name, define it too:
public function pages()
{
return $this->belongsToMany(Page::class, 'custom_pivot_table');
}
Something like this ?
$datas = Pages::where( ##your conditions### )->get()->inArray();
$countries = Countries::pluck('name','id'); // return array of id=>name
foreach($datas as $key=>$data) {
$c = [];
foreach(explode(',',$data['countries']) as $country_id) {
$c[]=$countries[$country_id];
//or
$c[]= ['id'=>$country_id,'name'=>$countries[$country_id]];
}
$datas[$key]['countries']= $c;
}

Laravel order by related table not working

I have this structure.
class Product extends Model{
public function office()
{
return $this->belongsTo(Office::class,'office_id');
}
}
I want to list products order by office.name.
this is the query
$res = \App\Product::with(['office' => function($q){
$q->orderBy('offices.name','asc');
}])->get();
this is the output loop
foreach($res as $key => $val){
print "<br />user: ".$val->id.", office: ".$val->office->id;
}
this is the Product data:
+----+--------+
| id | name |
+----+--------+
| 1 | Life |
| 2 | Cars |
| 3 | Health |
| 4 | House |
+----+--------+
this is the data in Office
+----+----------------+
| id | name |
+----+----------------+
| 1 | First office |
| 2 | working office |
+----+----------------+
The order by is not affecting the result.
same result, the order by like not existed.
Thanks
In your code you are simply "ordering" the offices by name, which means if each product had many offices, it would sort the offices alphabetically.
To sort (OrderBY()) a collection, the column has to be an attribute of the collection object. One solution could be to Join your models. SOmething like this might help you.
$res = Product::with('office')
->join('offices', 'products.office_id', '=', 'offices.id')
->select('products.*', 'offices.name')
->orderBy('office.name')
->get();

Query data based on pivot table

I have a database design which essentially takes the following form (I have removed a lot of fields as they are not really needed for demonstration purposes). I have a users table
users
+----+---------------+-----------------+
| id | name | email |
+----+---------------+-----------------+
| 1 | ProjectA | Something |
+----+---------------+-----------------+
A user can have many projects
projects
+----+---------------+-----------------+-----------------+
| id | name | description | user_id |
+----+---------------+-----------------+-----------------+
| 1 | ProjectA | Something | 1 |
+----+---------------+-----------------+-----------------+
So that is straight forward enough and very easy to query. If I want all projects for the logged in user I can do
$loggedInUser = Auth::user()->getFirstName() . ' ' . Auth::user()->getLastName();
$loggedInUserId = User::where('userName', '=', $loggedInUser)->first();
$projectss = Project::all()->where('user_id', $loggedInUserId);
This is where things get a little more tricky. I have a pivot table for a users groups. It is essentially this
users_user_groups
+----+---------------+-----------------+
| id | user_id | group_id |
+----+---------------+-----------------+
| 1 | 1 | 2 |
+----+---------------+-----------------+
I then have a user_groups table
user_groups
+----+---------------+
| id | group_name |
+----+---------------+
| 1 | Group A |
+----+---------------+
If I want to find what groups a user is a part of I can do
$userGroups = Auth::user()->getGroups();
My question is this. Above, I demonstrate how I can get all projects for a user. Now I know there is a user_group called Group A. What I essentially want to do is get all projects where the user is apart of Group A. So if 5 users create a project and they are all in Group A, then I should be returned 5 projects.
How would I go about doing something like this?
Thanks
Firstly you can get user id using simply Auth::user()->id
Assuming you are trying to get all the projects that belongs to users of a group You can do this.
$group = Group::with('users.projects')->find(1);
Group model
public function users()
{
return $this->belongsToMany('App\User');
}
User Model
public function projects()
{
return $this->hasMany('App\Project');
}
Of course you would have to make the appropriate relation methods depending on the forign/primary keys you used.

Resources