Laravel distinct on join one to many - php

I've found a couple of questions online similar to mine, but I can't seem to find a working answer.
I have 2 tables
USER
ID | FIRSTNAME | EMAIL_ADDRESS
1 | Joe Bloggs | Joe#bloggs.com
STATUS
ID | USER_ID | STATUS | DATE
1 | 1 | 'In' | 2018-06-04 09:01:00
2 | 1 | 'Out' | 2018-06-04 09:00:00
I need to be able to Join the 2 tables together but only get the most recent status column by date, like this
ID | FIRSTNAME | EMAIL_ADDRESS | STATUS_ID | STATUS | DATE
1 | Joe Bloggs | Joe#bloggs.com | 1 | 'In' | 2018-06-04 09:01:00
I need to be able to run extra query builder arguments like where, because the user has the ability to pass in filters and search parameters if they require, so to be able to use the status table columns in my query builder, i'm doing a join like this
$users = Users::join('status', 'status.user_id', '=', 'user.id')->distinct('user.id');
Which then allows me to pass in any search parameters if I need them
if(!empty($request->search)){
$param = $request->search;
$users = $users->where(function($query) use ($param){
$query->where('users.firstname', 'like', '%'.$param.'%')
->orWhere('users.email_address', 'like', '%'.$param.'%');
});
}
if(!empty($request->dateFrom)){
if(!empty($request->dateTo)){
$users = $users->whereRaw('DATE(status.date) BETWEEN ? AND ?', [$request->dateFrom, $request->dateTo]);
} else {
$users = $users->whereRaw('DATE(status.date) BETWEEN ? AND DATE(NOW())', [$request->dateFrom]);
}
}
Then run my get() at the end
if($method == 'paginate'){
$users = $users->paginate(10);
} else {
$users = $users->get();
}
This returns the following
ID | FIRSTNAME | EMAIL_ADDRESS | STATUS_ID | STATUS | DATE
1 | Joe Bloggs | Joe#bloggs.com | 1 | 'In' | 2018-06-04 09:01:00
2 | Joe Bloggs | Joe#bloggs.com | 1 | 'Out' | 2018-06-04 09:00:00
I need to be able to use the foreign table columns as arguments in my Where functions, but I need to only return 1 row per user. How do I run a join, but only return 1 row for each of my users?

To get latest record for each user you can use a self join for status table
select u.*,s.*
from user u
join status s on u.id = s.user_id
left join status s1 on s.user_id = s1.user_id
and s.date < s1.date
where s1.user_id is null
Using query builder you might rewrite it as
DB::table('user as u')
->select('u.*', 's.*')
->join('status as s', 'u.id ', '=', 's.user_id')
->leftJoin('status as s1', function ($join) {
$join->on('s.user_id', '=', 's1.user_id')
->whereRaw(DB::raw('s.date < s1.date'));
})
->whereNull('s1.user_id')
->get();
Laravel Eloquent select all rows with max created_at
Laravel - Get the last entry of each UID type
Laravel Eloquent group by most recent record

Since you are using Laravel lets make the solution a bit more understandable and easier:
First Lets create the models for each table:
class User extends Model
{
public $timestamps = false;
protected $fillable = [
'FIRSTNAME',
'EMAIL_ADDRESS'
];
public function status(){
return $this->hasMany(\App\Status::class);
}
}
Now lets create the Status Model:
class Status extends Model
{
public $timestamps = false;
protected $casts = [
'USER_ID' => 'int',
];
protected $fillable = [
'USER_ID',
'STATUS',
'DATE'
];
public function user()
{
return $this->belongsTo(\App\User::class);
}
}
Now you can use Eloquents like this:
$result=User::whereHas('Status', function($q){
$q->where('date', $current_date);
})->distinct('id')->get();
Hope it Helps!

Related

How I get users which are created by Auth::user

I have two table users and customer_details. I want to get users which are created by Auth::user(). The created_by column is in customer_details table.
User Table
| id | name | email | status |
|-----------------------------------------------|
| 1 | Admin | admin#email.com | Active |
| 2 | Customer | user#email.com | Active |
CustomerDetails Table
| id | user_id | added_by | address |
|-------------------------------------------|
| 1 | 2 | 1 | NY City |
This is my query
$customers = User::role('Customer')->whereIn('status', ['Active'])->get();
Want to get records where added_by is current auth user
$customers = User::role('Customer')->whereIn('added_by', Auth::id())->get();
I think this should help
here we are using Auth::id() to get the id of the current user and then using eloquent to search for it.
I am considering that here added_by column contains the ID;
Create a relation in your CustomerDetail model:
public function addedBy()
{
return $this->belongsTo(User::class, 'added_by');
}
Then, you can query using this relation:
CustomerDetail::whereHas('addedBy', function($query) {
return $query->where('id', auth()->id());
})->get();
This query returns all customer created by the user current logged in.
To get all users with it's customers created by the current logged in user, add a new relation, now to the user model:
public function customerDetail()
{
return $this->hasOne(CustomerDetail::class, 'added_by');
}
and query users with customers created byt the logged in user:
User::role('Customer')->whereHas('customerDetail', function($query) {
return $query->where('added_by', auth()->id());
})
->whereIn('status', ['Active'])
->get();

Laravel 5.6 Eloquent ORM where join table

I am dealing with Eloquent ORM collections and query builders. I am trying to figure out how to join and use "where" in a collection, like in query builder.
For example, I have the following tables:
Users:
ID | Name | Last name
-------------------------
1 | Martin | Fernandez
2 | Some | User
Persons:
ID | Nick | User_ID | Active
----------------------------------
1 | Tincho | 1 | 1
Companies:
ID | Name | User_ID | Active
----------------------------------
1 | Maramal| 1 | 0
2 | Some | 2 | 1
This is an example, the tables I am working on have more than 30 columns each one. I want to select all the user that are active.
Usually I would do a query like:
SELECT *
FROM users
LEFT JOIN persons ON users.id = persons.user_id
LEFT join companies ON users.id = companies.user_id
WHERE persons.active = 1
OR companies.active = 1
That can be translated to Laravel Query Builder like:
DB::table('users')
->leftJoin('persons', 'users.id', '=', 'persons.user_id')
->leftJoin('companies', 'users.id', '=', 'companies.user_id')
->where('persons.active', 1)
->orWhere('companies.active', 1)
->get();
But what I want to use is a Laravel Eloquent ORM Collection, until now I am doing the following:
$users= User::orderBy('id',' desc')->get();
foreach($users as $k => $user) {
if($user->company && !$user->company->active || $user->person && !$user->person->active) {
unset($users[$k]);
}
... and here a lot of validations and unsets ...
}
But I know that at this point, I already grabbed all the users instead those who are active.
How would I achieve what I did with query builder within a collection? Thanks in advance.
This should do it:
$users = User::whereHas('companies', function($q) {
$q->where('active', true);
})->orWhereHas('persons', function($q) {
$q->where('active', true);
})->with(['companies', 'persons'])->orderBy('id', 'desc')->get();

Laravel 5.5 User model and friends relationship (belongsToMany) by multiple columns

Problem
I created a simple friendship relationship for my Laravel app which all worked ok until I noticed that when I queried the friendship of a user it would only search the current user on the UID1 field.
Since friendships are in essence a two-way relationship, Im trying to find a way in a laravel Model to retrieve ALL friendships relations by multiple columns.
Current Implementation
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'friends', 'uid1');
}
Ideal Implementation
public function friends()
{
$a = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
$b = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid2');
return combine($a,$b);
}
Table Structure
+----------------------+
| users table |
+----------------------+
+----| id: primary UserID |
| | fname: string |
| +----------------------+
|
|
| +----------------------+
| | friends table |
| +----------------------+
| | id: primary iD |
| | |
+----| uid1: user_id |
| | |
+----| uid2: user_id |
+----------------------+
The current implementation will only result in 1 of these records returning if the Current UserID = 1 as per the data in the friends table below.
+-------------------------------+
| friends table (data) |
+--------|---------|------------+
| id | uid1 | uid2 |
+--------|---------|------------+
| 1 | 1 | 7 |
| 2 | 7 | 1 |
| 3 | 9 | 1 |
+-------------------------------+
User Model
<?php
namespace App\Modules\Users\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'users';
protected $fillable = [
'username', 'email', 'password', .... .
];
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
}
Environment
Server = Homestead/linux
PHP = 7
MySQL
Update
I have a FriendShip helper class I created which does something similar, however in this function I pass in the UserID explicitly
Friendship::where( [
[ 'uid1' ,'=', $uid],
])->orWhere( [
[ 'uid2', '=', $uid]
])->all();
You can add additional conditions when you're declaring relationship by simply chaining it.
<?php
//...
class User extends Model {
//...
public function friends() {
return $this->hasMany(/*...*/)->orWhere('uid2', $this->id);
}
//...
But keep in mind that eloquent is not grouping the first conditions of relation in parenthesis so you might end with SQL that will not work as expected in some cases (if using or, and should be fine)
For example the above might result in a SQL that looks like this
SELECT * FROM users_friends WHERE uid1 = ? AND uid1 IS NOT NULL OR uid2 = ?
Which is a correct SQL statement but without grouping you will not get the result that you're expecting.
Another way is to use accessor and two separate relationships
<?php
//...
public function friends1() {
return $this->belongsToMany(User::class, 'users_friends', 'uid1');
}
public function friends2() {
return $this->belongsToMany(User::class, 'users_friends', 'uid2');
}
public function getFriendsAttribute() {
return $this->friends1->merge($this->friends2);
}
//...
But this way you get two separate trips to DB.

Laravel leftJoin AS

How can I make that query in Laravel Eloquent or Fluent?
DUELS
|id|userId1 | UserId2
-------------------------
|1| 1 | 4 |
|2| 3 | 2 |
|3| 2 | 1 |
-------------------------
USERS
|id| firstName |
----------------
|1| Bob |
|2| Hans |
|3| Jerome |
|3| Katy |
----------------
Query: get the names of the users in the duels where the user with $userId is participating:
SELECT u1.firstName AS user1FirstName, u2.firstName AS user2FirstName
FROM duels
LEFT JOIN users AS u1
ON userId1 = u1.id
LEFT JOIN users AS u2
ON userId2 = u2.id
WHERE userId1 = $userId || userId2 = $userId
Using Laravel's Fluent, to perform that query you need to do the following:
DB::table('users')->join('duels', function($join) use ($userId){
$join->on('users.id', '=', 'duels.userId1')
->orOn('users.id', '=', 'duels.userId2')
->where('users.id', '=', $userId);
})->get();
Using Laravel's Eloquent, however, you may consider the user as either first player, or as second player.
In your User model, define the above two relationships as such:
class User extends Eloquent{
/**
* ...
*/
public function duelsAsFirstPlayer(){
return $this->belongsToMany( 'App\User', 'duels', 'user_id_1', 'user_id_2');
}
public function duelsAsSecondPlayer(){
return $this->belongsToMany( 'App\User', 'duels', 'user_id_2', 'user_id_1');
}
}
Now, in order to get all the users the user with $userId has duels with, query the User model as such:
as first player:
$users = App\User::find($userId)->duelsAsFirstPlayer()->get();
or as second player:
$users = App\User::find($userId)->duelsAsSecondPlayer()->get();

Joining Tables in Laravel 4.2 Eloquent

I'm not so good at making queries using Laravel Eloquent. I've two tables
stories table
------------------------------------------------------------------
id | title | body | author_id |...
------------------------------------------------------------------
1 | Story 1 | Once a.. | 2
2 | Story 2 | There is | 4
3 | Something | You are. | 2
activities table
------------------------------------------------------------------
id | story_id | liker_id |...
------------------------------------------------------------------
1 | 2 | 2
Here author_id & liker_id are actually user_id. I want to get the Stories authored and liked by a specific user to display these stories in his profile.
I want to use the Eloquent ORM. I tried something like this using query builder
$stories = DB::table('stories')
->join('activities', function($join)
{
$join->on('stories.author_id', '=', 'activities.liker_id')
})
->where('stories.author_id', $author_id)
->get();
return $stories;
I can get story_id for a specific liker_id by join but couldn't get the details from stories table using story_id in a Single query.
Here is simple method with query builder to get Stories authored and liked by a specific user
$author_id = 1;
$stories = DB::table('stories')
->join('activities', 'stories.author_id', '=', DB::raw('activities.liker_id AND stories.id = activities.story_id'))
->Where('stories.author_id', $author_id)
->get();
//select * from `stories` inner join `activities` on `stories`.`author_id` = activities.liker_id AND stories.id = activities.story_id where `stories`.`author_id` = 1"
with Eloquent you can do as following create 2 model file
1. Story model (Story.php)
2. Activity Model (Activity.php)
Story.php
class Story extends Eloquent {
public function activities()
{
return $this->hasMany('Activity');
}
}
Activity.php
class Activity extends Eloquent {
public function story()
{
return $this->belongsTo('Story');
}
}
than you can write function within Story to get data as your need
$stories = Story::with('activities')
->where(DB::raw('stories.id = activities.story_id'))
->Where('stories.author_id', $author_id)
->get();
// haven't tested with eloquent but it should work

Categories