Laravel, find ids using query where those ids are in another table - php

I have two tables, school_users and users. I need to create a query, using Eloquent, that gets all users where user_id equal school_id.
so the result must be more than one user, so that also I need to group the result by school_id
thank you in davance
Relations:
User Model:
public function school()
{
return $this->hasMany(SchoolUser::class);
}
SchoolUser Model:
public function user()
{
return $this->hasMany(User::class);
}
School_users table:
+----+---------+------------+-------------+
| id | user_id | school_id | created_at |
+----+---------+------------+-------------+
| 1 | 79 | 79 | <SOME TIME> |
| 2 | 85 | 79 | <SOME TIME> |
| 3 | 86 | 85 | <SOME TIME> |
| 4 | 87 | 85 | <SOME TIME> |
+----+---------+------------+-------------+
users table:
+----+
| id |
+----+-
| 79 |
| 85 |
| 86 |
| 87 |
+----+-
User Model:
public function getUsers()
{
return $this
->leftJoin('school_users', $this->table . '.id', '=', 'school_users.school_id')
->select(
$this->table . '.*',
'school_users.school_id as school_id'
)
->whereIn('users.id', '=', 'school_users.school_id')
->orderBy('id', 'desc')
->get();
}

Use whereColumn to filter user_id equal to school_id,
and use join instead of leftjoin:
public function getUsers()
{
return $this
->join('school_users', function($join) {
$join->on('school_users.user_id', '=', $this->table.'.id')
->whereColumn('school_users.user_id', 'school_users.school_id');
})
->select
(
$this->table.'.*',
'school_users.school_id as school_id'
)
->orderBy($this->table.'.id','desc')
->get();
}

Related

Laravel impossible where query

I'm working on a filter for some products. I have the majority of it working however I am encountering an error with an impossible where clause.
The table contains multiple rows for a single product and I am trying to match multiple criteria per product, which is causing it to fail.
If you have an opinion on this, or possibly a way to fix this, I would greatly appreciate it.
The database table looks like this:
--------------------------------------------
|id | FilterKey | filterValue | product_id |
--------------------------------------------
|1 | Colour | Gunmetal | 1 |
|2 | Colour | Silver | 1 |
|3 | Size | 750cc | 1 |
|4 | Size | 1000cc | 1 |
|5 | Colour | Red | 2 |
|6 | Colour | Blue | 2 |
|7 | Size | 750cc | 2 |
|8 | Size | 1000cc | 2 |
--------------------------------------------
And the filter looks like this:
public function scopeFilterProduct($query, $filters)
{
$this->filters = $filters;
if (count ($this->filters) === 1 && isset($this->filters[0]))
{
return $query;
}
$query->join('product_filters', 'products.id', '=', 'product_filters.product_id')->Where(function($query){
foreach ($this->filters as $filter => $vals)
{
$this->filter = $filter;
$this->vals = $vals;
$query->Where(function ($query){
$query->Where('filterKey', $this->filter);
$query->Where(function($query){
foreach ($this->vals as $val){
$query->orWhere('filterValue', $val);
}
$this->vals = null;
});
});
$this->filter = null;
};
});
return $query;
}
This then outputs the following SQL statement:
select
distinct
`products`.`id`
, `product_id`
from
`products`
inner join
`product_filters`
on
`products`.`id` = `product_filters`.`product_id`
where
(
(`filterKey` = 'Colour' and (`filterValue` = 'gunmetal'))
and
(`filterKey` = 'Size' and (`filterValue` = '750cc'))
)
and
`products`.`deleted_at` is null
If selected, as in the screenshot, then only 'product one' should be present on the page.
The scope you have added in my opinion is wrong. Even your database structure is incorrect in my opinion. Here is how i would structure this:
Filters Table
This model will hold all the filter values. For example, Colour, Size etc. Here is how the filter table will be structured:
-----------------
|id | name |
-----------------
|1 | Colour |
|2 | Size |
-----------------
So your eloquent model become something like this:
class Filter extends Model
{
protected $fillable = ['id', 'name'];
public function products()
{
return $this->belongsToMany(Product::class, 'products_filters');
}
}
Products Table
Your product models becomes:
class Product extends Model
{
public function filters()
{
return $this->belongsToMany(Filter::class, 'products_filters');
}
}
products_filters Table
After the above changes, here is how the table will be structured:
--------------------------------------------
|id | filter_id | filterValue | product_id |
--------------------------------------------
|1 | 1 | Gunmetal | 1 |
|2 | 1 | Silver | 1 |
|3 | 2 | 750cc | 1 |
|4 | 2 | 1000cc | 1 |
|5 | 1 | Red | 2 |
|6 | 1 | Blue | 2 |
|7 | 2 | 750cc | 2 |
|8 | 2 | 1000cc | 2 |
--------------------------------------------
Now you can simply query the filters table, then get associated products for all filters. After that you simply need to compile a list of unique products.
Unqiue products based on selected filters.
$ids = [];
$products = new \Illuminate\Support\Collection();
foreach($filters as $filter) {
foreach($filter->products as $product) {
if(!in_array($product->id, $ids)) {
$ids[] = $product->id;
$products->push($product);
}
}
}
return view('results', compact('products'));
In your view, you need to write:
#foreach($products as $product)
// Your product block HTML
#endforeach

Eloquent Relations With Multiple Columns

So I have the following match table which contains the numbers of the teams that participated in that match. I want to set up a relationship with the teams which looks something like this:
Teams Table
| id | number | name | etc |
| 1 | 1234 | Example | etc |
| 2 | 2345 | Example | etc |
etc...
Matches Table
| id | match | red1 | red2 | blue1 | blue2 |
| 1 | 1 | 1234 | 1710 | 673 | 2643 |
| 2 | 2 | 2345 | 1677 | 4366 | 246 |
etc...
I want to have something like $this->match->where("match", "=", "2")->first()->teams();.
I have tried using hasMany() but I can't seem to get to use the red1, red2, blue1, blue3 columns.
What I have tried:
class Matches extends Model
{
protected $table = "match_table";
protected $fillable = [
"match_id",
"time",
"bluescore",
"redscore",
"red1",
"red2",
"red3",
"blue1",
"blue2",
"blue3",
];
public function teams()
{
return $this->hasMany("App\Models\Teams", "number", ["red1", "red2", "blue1", "blue2"]);
}
}
What I ended up doing was just looping through each column I wanted and then just returning a new Collection with the results in it.
public function teams()
{
$result = [];
foreach($this::$teamColumns as $column) {
$result[] = $this->hasMany("App\Models\Teams", "number", $column)->first();
}
return new Collection($result);
}

Relationship between 4 tables Laravel 5.1

I need to show feeds with total comments, and total likes on that feed with the detail of users who have commented.
Feeds Table
| id | movie_id | user_id | description |
|----|----------|----------|-------------|
| 1 | 1 | 1 | Lorem Ipsum |
Comments Table
| id | feed_id | user_id | comment |
|----|-------- |----------|-----------|
| 1 | 1 | 2 | comment 1 |
| 2 | 1 | 3 | comment 2 |
Likes Table
| id | feed_id | user_id |
|----|-------- |----------|
| 1 | 1 | 2 |
| 2 | 1 | 3 |
Users Table
| id | username| email |
|----|-------- |--------|
| 1 | a | a#a.com|
| 2 | b | b#b.com|
| 3 | c | c#c.com|
Relations
Feed.php
public function user () {
return $this->belongsTo('App\User');
}
public function likes () {
return $this->hasMany('App\Like');
}
public function comments () {
return $this->hasMany('App\Comment');
}
User.php
public function feeds () {
return $this->belongsToMany('App\Feed');
}
public function like () {
return $this->belongsTo('App\Like');
}
public function comment () {
return $this->belongsTo('App\Comment');
}
Like.php
public function user () {
return $this->belongsTo('App\User');
}
public function feed () {
return $this->belongsTo('App\Feed');
}
Comment.php
public function user () {
return $this->belongsTo('App\User');
}
public function feed () {
return $this->belongsTo('App\Feed');
}
Now I need to fetch all feeds (I have done with this), with comments count, likes count, and users details who have commented.
Ho can I get that in single query using Eloquent.
Try this
$commentsCount = \App\Models\Comment::select('feed_id',\DB::raw('count(id) as comments_count'))->groupBy('feed_id')->toSql();
$likesCount = \App\Models\Like::select('feed_id',\DB::raw('count(id) as likes_count'))->groupBy('feed_id')->toSql();
$records = \DB::table('feeds as f')
->leftJoin('comments as c','f.id','=','c.feed_id')
->leftJoin('users as u','c.user_id','=','u.id')
->leftJoin(\DB::raw('('.$commentsCount.') as k'),'f.id','=','k.feed_id')
->leftJoin(\DB::raw('('.$likesCount.') as l'),'f.id','=','l.feed_id')
->select('f.id as fid','f.description','u.id as uid','u.name','u.email','k.comments_count','l.likes_count')
->orderBy('fid')
->get();
$transform = function(array $records){
$records = collect($records)->groupBy('fid');
return $records->transform(function($items){
$feed['id'] = $items->first()->fid;
$feed['description'] = $items->first()->description;
$feed['count'] = [
'likes' => is_null($items->first()->likes_count) ? 0 : $items->first()->likes_count,
'comments' => is_null($items->first()->comments_count) ? 0 : $items->first()->comments_count,
];
$feed['users'] = $items->transform(function($user){
return is_null($user->uid) ? [] : ['id'=>$user->uid,'name'=>$user->name,'email'=>$user->email];
});
return $feed;
});
};
return array_values($transform($records)->toArray());
you can swap the closure function with other function. like
$this->transform($records);
You can simply access all those properties through the functions defined.
Example:
$feed = Feed::find($id);
foreach($feed->likes() as $like){
echo $like->user()->get('username');
}
And so forth. Up to a point when you call ->get(), you are accessing an object, which can traverse all of these.

Eloquent query where column is in another table

I have two tables, posts and likes. I need to create a query, using Eloquent, that gets all posts that have been liked by a specific user_id.
In other words, it should be something like this:
SELECT * FROM posts p LEFT JOIN likes l ON p.id = l.post_id WHERE l.user_id = 2 ORDER BY l.created_at DESC
posts table:
+----+---------+------------+-------------+
| id | user_id | message | created_at |
+----+---------+------------+-------------+
| 1 | 2 | Hello! | <SOME TIME> |
| 2 | 3 | World! | <SOME TIME> |
| 3 | 2 | Something. | <SOME TIME> |
| 4 | 2 | Another. | <SOME TIME> |
+----+---------+------------+-------------+
likes table:
+----+---------+---------+-------------+
| id | post_id | user_id | created_at |
+----+---------+---------+-------------+
| 1 | 1 | 2 | <SOME TIME> |
| 2 | 2 | 2 | <SOME TIME> |
| 3 | 1 | 3 | <SOME TIME> |
| 4 | 3 | 2 | <SOME TIME> |
+----+---------+---------+-------------+
Here is my Postclass:
<?php
class Post extends Eloquent {
protected $table = 'posts';
public function likes()
{
return $this->hasMany('Like');
}
}
And the Like class:
<?php
class Like extends Eloquent {
protected $table = 'likes';
public function post()
{
return $this->belongsTo('Post');
}
}
How can I do this?
This should work:
$userId = //however you get the userid here.
$posts = Post::whereHas('likes', function ($q) use ($userId) {
$q->where('user_id', $user_id);
})->get();
You can use Laravel's DB class to perform joins on two or more tables, following is how your query will be executed in laravel:
$users = DB::table('posts')
->leftJoin('likes', 'posts.id', '=', 'likes.post_id')
->select('posts.*', 'likes.*')
->where('likes.user_id', '=', '2')
->orderBy('likes.created_at', 'desc')
->get();
Don't forget to use DB class on the top of your controller;
If you want to do it with eloquent, you should do the follwing:
$result = Post::whereHas('likes', function ($q) use($user_id)
{
$q->where('user_id', $user_id);
})
->orderBy('likes.created_at')
->get();

Laravel LeftJoin where

I have some problems with my eloquent model, where I try to join two different tables in one
Now I have two tables like.
First tables name "company_saved_cv"
|id|company_id|worker_id |
--------------------------
|1| 2 | 61 |
|3| 3 | 66 |
|4| 2 | 69 |
--------------------------
Second tables name "workers"
|id|location|name_and_surname|
------------------------------
|61|London | John John |
|62|London | John John |
|66|London | John John |
|67|London | John John |
|68|London | John john |
And I whana get table like this.
|id|location|name_and_surname|worker_id|
---------------------------------------|
|61|London | John John | 61 |
|62|London | John John | NULL |
|66|London | John John | 66 |
|67|London | John John | NULL |
|68|London | John john | NULL |
where is my model function
public static function CvSearch($interested_field, $location)
{
$match = "MATCH( `interested_fields`) AGAINST (?)";
$query = Worker::select('workers.name_and_surname', 'workers.id', 'workers.location','company_saved_cv.worker_id')
->leftJoin('company_saved_cv', function($leftJoin)
{
$leftJoin->on('company_saved_cv.worker_id', '=', 'workers.id')
->where('company_saved_cv.company_id', '=', Session::get('company_id') );
})
->where('workers.location', '=', $location)
->whereRaw($match, array($interested_field))
->orderBy('workers.created_at')
->paginate(10);
return $query;
}
If I comment this line:->where('company_saved_cv.company_id', '=', Session::get('company_id') ); It is working, but I need get only rows from workers table where company_id = 2 (in my example);
Session::get('company_id') = 2
I will check it by logging it in laravel.log file.
I fink it is problem with where('company_saved_cv.company_id', '=', Session::get('company_id') ); request, but I can't figure it out, maybe some one can help me?
I solve this problem with this code
$query = Worker::select('workers.name_and_surname', 'workers.id', 'workers.location','company_saved_cv.worker_id')
->leftJoin('company_saved_cv', function($leftJoin)use($company_id)
{
$leftJoin->on('workers.id', '=', 'company_saved_cv.worker_id');
$leftJoin->on(DB::raw('company_saved_cv.company_id'), DB::raw('='),DB::raw("'".$company_id."'"));
})
More or less like this:
$directoryTypeId = 1;
Node::query()
->leftJoin('directories', 'directories.id', '=', 'nodes.directory_id')
->leftJoin('directory_types', function ($leftJoin) use ($directoryTypeId) {
$leftJoin
->on('directory_types.id', '=', DB::raw($directoryTypeId))
->on('directory_types.COLUMN_1', '=', 'directories.COLUMN_2');
})
->select([
'nodes.id as node_id',
'directories.name',
'directory_types.id as type_id',
]);
Well when you use LEFT JOIN with where it acts as an INNER JOIN
Use LEFT JOIN and WHERE like
SELECT workers.name_and_surname, workers.id, workers.location,company_saved_cv.worker_id
FROM workers LEFT JOIN company_saved_cv
ON company_saved_cv.worker_id= workers.id
WHERE company_saved_cv.company_id = 2
OUTPUT
|id|location|name_and_surname|worker_id|
---------------------------------------|
|61|London | John John | 61 |
|66|London | John John | 66 |
Use LEFT JOIN and AND like
SELECT workers.name_and_surname, workers.id, workers.location,company_saved_cv.worker_id
FROM workers LEFT JOIN company_saved_cv
ON company_saved_cv.worker_id= workers.id
AND company_saved_cv.company_id = 2
OUTPUT
|id|location|name_and_surname|worker_id|
---------------------------------------|
|61|London | John John | 61 |
|62|London | John John | NULL |
|66|London | John John | 66 |
|67|London | John John | NULL |
|68|London | John john | NULL |
New query
$query = Worker::select('workers.name_and_surname', 'workers.id', 'workers.location','company_saved_cv.worker_id')
->leftJoin('company_saved_cv', function($leftJoin)
{
$leftJoin->on('company_saved_cv.worker_id', '=', 'workers.id')
->on('company_saved_cv.company_id', '=', Session::get('company_id') );
})
You can easily use the Model for it. The last table, you can remove the location because you can get it with and from the model. Create easily a many-2-many relationship or something you want. Check the docs: http://laravel.com/docs/4.2/eloquent#relationships

Categories