how to group by item many to many query builder laravel - laravel

I have comics and categories related many to many through pivot tables. I use join and groupBy caterories.id but it doesn't group categories same comics id.
If I do not use the group
$result = DB::table('comics')
->select('comics.name','categories.title')
->join('category_comic', 'comics.id', '=', 'category_comic.comic_id')
->join('categories', 'category_comic.category_id', '=', 'categories.id')
->get();
I want each comic group category
(source: uphinh.org)

First of all
try tou use Laravel Eloquent Relationship and its really cool and very easy to use
In Eloquent Method
In Comics Model
add relationship function
public function cat(){
return $this->hasOne(ComicCategory::class,'id','comic_id'); //ComicCategory::class is your category_comic model
}
Then you just need you Comic Model to get a group of your category com
$result = Comic::with('cat')->get(); //Commic is your model
In query Builder, you need to group manual using foreach
$result = DB::table('comics')
->select('comics.name','categories.title')
->join('category_comic', 'comics.id', '=', 'category_comic.comic_id')
->join('categories', 'category_comic.category_id', '=', 'categories.id')
->get();
$result = json_decode(json_encode($result), TRUE);
$new_result = [];
foreach($result as $row){
$arr[$row['id']]['name'] = $row['name'];
$arr[$row['id']]['cat'][] = $row['title'];
}
and finally rearange the key
$new_result = array_values($new_result );
PS : thats array method, i never group using object method

Related

Trouble converting an SQL query to Eloquent

Trying to get this query to work in eloquent
A user can be in multiple teams however I want to generate a list of users NOT in a specific team. The following SQL query works if executed directly but would like to make it cleaner by converting it to eloquent
SELECT * FROM users LEFT JOIN team_members ON team_members.member_id = users.id WHERE NOT EXISTS ( SELECT * FROM team_members WHERE team_members.member_id = users.id AND team_members.team_id = $team_id )
This should provide a list of all the users that are not members of team $team_id
This is a guess ad you do not give much info on your Eloqent models but here is a hint of where to go:
User::doesnthave('teamMembers', function($builder) use($team_id){
return $builder->where('team_members.team_id');
});
That is assuming you have a "User" model with a "teamMembers" relationship setup on it
You may have a closer look in the Laravel docs for doesntHave
Laravel 5.8
Let's assume you have model name "User.php"
& there is method name "teamMembers" in it.
Basic
$users = User::doesntHave('teamMembers')->get();
Advance
use Illuminate\Database\Eloquent\Builder;
$users = User::whereDoesntHave('teamMembers', function (Builder $query) {
$query->where('id', '=', {your_value});
})->get();
You can find details description in this link >>
https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-absence
Laravel 5.2
Example:
DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Check this link for advance where clause:
https://laravel.com/docs/5.2/queries#advanced-where-clauses
You can use below example
$list = User::leftJoin('users', 'users.id', '=', 'team_members.member_id')
->whereNotExists(function ($query) use ($team_id) {
$query->from('team_members')
->whereRaw('team_members.member_id = users.id')
->where('team_members.team_id', '=', $team_id);
})
->get();

Laravel Eloquent: orderBy related table

I would like to order result of eloquent by field on the other related table.
I have users table. Every user has one profile. Profile has sponsored (which is boolean) field. So when I would like to get all users, I want to display first sponsored users, then non sponsored.
public function profile(){
return $this->hasOne('App\Doctor');
}
There are two ways:
1)You have to join tables,
User::join('profiles','users.id','=','profile.user_id')->orderBy('sponsored','DESC')->get()
2)Order by eager loading
User::with(array('profile' => function($query) {
$query->orderBy('sponsored', 'DESC');
}))
->get();
Try this one
User::leftJoin('profile', 'user.id', '=', 'profile.user_id')
->orderBy('profile.sponsored', 'ASC')
->get();
I highly recommend not using table joins as it would fail you on the scale.
A better solution is to get users, get their profiles and then sort them using laravel collection methods.
You can use this sample to achieve this solution.
//get all users
$users = User::all();
//extract your users Ids
$userIds = $users->pluck('id')->toArray();
//get all profiles of your user Ids
$profiles = Profile::whereIn('user_id', $userIds)->get()->keyBy('user_id');
//now sort users based on being sponsored or not
$users = $users->sort(function($item1, $item2) use ($profiles) {
if($profiles[$item1->id]->sponsored == 1 && $profiles[$item2->id]->sponsored == 1){
return 0;
}
if($profiles[$item1->id]->sponsored == 1) return 1;
return -1;
});
You can check this link which explains on laravel collection sorts.
$order = 'desc';
$users = User::join('profile', 'users.id', '=', 'profile.id')
->orderBy('profile.id', $order)->select('users.*')->get();

october cms (laravel) where query

I have a some problem with filter query. I need to do somethink like
select painting from artist_painting where type=$_GET['type'] AND material=$_GET['material'] and artist_slug =$_GET['artist_slug'] ORDER BY painting DESC
I have a pivot table artist_painting and artist. 'artist_slug' is in the 'artist' table
I do
$this['painting'] = Painting::whereHas('artist', function($q)
{
$q->where('artist_slug', '=', $this->param('slug'));
})->get();
but I do not know what to do next.
How can i do query in php code?
Short and dirty:
Painting::where('type',input("type"))
->where('material',input("material"))
->whereHas('artist', function($q)
{
$q->where('artist_slug', '=', $this->param('slug'));
})->get();
The explanation:
When you initialize a query a query builder instance is returned. Basically all methods on the query builder return the same instance so you can daisy chain them into one query.
But you can also just work on the query builder.
$query = Painting::where('type',input("type"));
or:
$query = $model->newQuery()// Where model is an intance of painting, for example new Painting();
Then you can just work on the query builder instance, pass it to other methods that might to do things.
function getPaintings($type, $material, $slug)
{
$query = Painting::where('type',$type);
$query->where('material', $material);
$this->findArtistBySlug($query, $slug);
return $query->get()
}
function findArtistBySlug($query, $slug)
{
$query->whereHas('artist', function($q) use ($slug)
{
$q->where('artist_slug', '=', $slug);
});
$query->with(['artist']);
}
You might want to read https://octobercms.com/docs/database/query
and https://laravel.com/docs/5.6/queries
I would solve this problem from the Artist's point of view:
$artist = Artists::where('artist_slug', $this->param('slug'))->with('paintings')->first();
All the paintings of the artist can be accessed by using $artist->paintings, which will be a Collection.

How to select instances for specific 'n' on m:n relationships?

I have two models Teacher and Category. These two have Many to Many relationship.
I want to get those teachers who have one category equal to "OLevels". Which method of eloquent is used for it or is there any other way I can get it?
Is there anyway to get it as:
$teachers = Teacher::where('category', '=', 'OLevels')->get();
You can use whereHas for that:
$category = 'OLevels';
$teachers = Teacher::whereHas('category', function($q) use ($category){
$q->where('name', $category);
})->get();
You could make use of eager loading with constraints
$teachers = Teacher::with(['category' => function($query)
{
$query->where('category', '=', 'OLevels');
}])->get();
Further info in the documentation.

Ordering Results from Related Tables in Eloquent and the Session

I have the following in my Event model in Laravel 4. The reason I am using QueryBuilder and not Eloquent is I need to have links in each column header in my results table in my view, that when clicked, order the results in asc or desc based on that column.
The issue I'm having is, if I use Eloquent, it won't work as most of the data is pulled through via relationships to other tables, so Eloquent can't find the required columns/fields.
public static function getEvents($perPage = 10)
{
$order = Session::get('event.order', 'start_date.desc');
$order = explode('.', $order);
$columns = array(
'events.id as id',
'title',
'locations.city as city',
'suppliers.name as supplier_name',
'venues.name as venue_name',
'start_date',
'courses.price as course_price',
'type',
'status',
'max_delegates as availability',
'tutors.first_name as tutor_first_name',
'tutors.last_name as tutor_last_name',
'contacts.first_name as d_first_name'
);
$events = DB::table('events')
->leftJoin('courses', 'course_id', '=', 'courses.id')
->leftJoin('suppliers', 'supplier_id', '=', 'suppliers.id')
->leftJoin('locations', 'location_id', '=', 'locations.id')
->leftJoin('venues', 'venue_id', '=', 'venues.id')
->leftJoin('event_types', 'event_type_id', '=', 'event_types.id')
->leftJoin('event_statuses', 'event_status_id', '=', 'event_statuses.id')
->leftJoin('tutors', 'tutor_id', '=', 'tutors.id')
->leftJoin('delegate_event', 'delegate_event.event_id', '=', 'events.id')
->leftJoin('delegates', 'delegates.id', '=', 'delegate_event.delegate_id')
->leftJoin('contacts', 'delegates.contact_id', '=', 'contacts.id')->groupBy('events.id')
->select($columns)
->orderBy($order[0], $order[1])
->paginate($perPage);
return $events;
}
If you look at my EventsController at the getOrder method:
public function getOrder($order)
{
Session::put('event.order', $order);
return Redirect::back();
}
You can see I am storing the order in the session and then in my model using that to sort the order of results.
Is there a way to do this in Eloquent the way I need to?
You know you can just add a join() to eloquent right?
So, as an example, if you have users and each user has some blog posts (i.e. user has_many blogs), you can output an eloquent model showing username and blog title, ordered by blog title, as follows:
user::join('blogs', 'blogs.id','=','users.blog_id')
->order_by('blogs.title', 'asc')
->select(array('users.username', 'blogs.title'))
->paginate(10);

Resources