I have a to and from columns which are integers from the users in my messages table, as I was building a chat like application on this part.
So I want to fetch all the messages of the currently logged on user. so this is the query
$all_messages = Message::where('from',$logged_user)->orWhere('to',$logged_user)->with('owner')->orderBy('created_at','desc')->get();
note that $logged_user variable is an integer / the authenticated users id
so from that,
but also I want to get also the messages between the logged_user and also the respondent_id or the id of the respondent or the user that I am trying to connect also.
So for example the currently logged on user_id is 2 and the respondent id is 3 I want the messages that have a from of 2 or 3 and also the respondent_id of 2 and 3 something like that
If I've understood the question right you're looking for the messages belonging to the conversation between two users, so what you're looking for should be following:
$loggedInUserId = 2;
$contactUserId = 3;
$messages = Message::query()
->where(function ($query) use ($loggedInUserId, $contactUserId) {
$query->where('sender_id', $loggedInUserId)
->where('recipient_id', $contactUserId);
})
->orWhere(function ($query) use ($loggedInUserId, $contactUserId) {
$query->where('recipient_id', $loggedInUserId)
->where('sender_id', $contactUserId);
})
->with('owner')
->orderBy('created_at', 'desc')
->get();
Also, if you're heavily relying on having to track "conversations" between two or more users you might think to aggregate them as threads.
Related
I am trying to create a chat app in Laravel. When a conversation is created between users, I don't want to record a user as host user. I would like to get a conversation filtered by given users. Example: If USER_1 and USER_2 belong to CONVERSATION_1, I want to filter out CONVERSATION_1 by USER_1 and USER_2 ids.
Here is my table structures.
conversations
id
product_id
conversation_users
id
conversation_id
user_id
Here is my conversation service.
class ConversationService
{
public static function first(User $user){
$admin = getAdmin();
$conversation = Conversation::whereHas("users", function($q) use($user, $admin){
$q->where("user_id", $user->id)->where("user_id", $admin->id);
})->first();
}
}
I know I can't use this statement. $q->where("user_id", $user->id)->where("user_id", $admin->id);
Could you please guide me how to filter a conversation by user ids?
Since the conversation must belong to both users explicitly, just double on the condition, one for each user
$conversation = Conversation::query()
->whereHas("users", function($q) use($admin){
$q->where("user_id", $admin->id);
})
->whereHas("users", function($q) use($user){
$q->where("user_id", $user->id);
})
->first();
Once you see this version of the code, it will tick that it's simple logic.
Very long time I searching for solution for this problem:
Lets say we have 2 tables one table is Clients table and second table is ClientAssignment table:
the ClientAssignment table is related to Clients table:
public function assignment()
{
return $this->hasOne(ClientAssignment::class, 'client_id');
}
now when I want to count how many ClientAssignment has Clients and i do it like that:
$users =[1,2,3,4 .....]
$userAssignments = array();
foreach ($users as $user) {
$user_assignments = Client::whereHas('assignment', function ($query) use ($user) {
$query->where('assigned_id', $user);
});
$ua['user_id'] = $user;
$ua['count'] = $user_assignments->count();
array_push($userAssignments, $ua);
}
The code works well but it hits the performance and query execution time ~20 + seconds on a relatively small table with 80k Clients,
My question if can be another way to do the same thing but with minimum performance and query execution time hit ?
According to your post, I think
Client --- hasOne ----> ClientAssignment <----- hasMany ---- User
[client_id, assigned_id]
So User can hasMany Client through ClientAssignment,
However, your client_id and assigned_id are all in client_assignment table. So you can not use hasManyThrough, this just like a pivot table;
Fortunately, you can directly count the client_id and get the assigned_id as user_id just use this pivot table.
The query is like this (Use distinct(client_id) for preventing the dirty records):
ClientAssignment::whereIn('assigned_id', $users)
->groupBy('assigned_id')
->select('assigned_id AS user_id',
DB::raw('COUNT(DISTINCT(client_id)) AS count'))
->get()->toArray();
And add assigned_id index to improve the performance.
$table->index('assigned_id');
Use the count()
Client::first()->assignments->count();
// Or
Client::find(ID)->assignments()->count();
// or ...
This question already has answers here:
Laravel eloquent selecting most recent row from joined table
(3 answers)
Closed 3 years ago.
I have two tables for example users and orders.
I have to join users with orders On users.id = orders.user_id - which is quite fine.
User table has one to many relation in orders table.
I have some conditions also, like orders.pay_type = 'xyz', 'orders.date = yesterday' , 'user.status = active' ..etc.
My problem is that I need to join my user table to the latest row of orders table correspond to that user_id.
Or need to fetch the latest details of that users orders table details along with user table data.
I already tried
->orderBy('orders.date')
->groupBy('orders.user_id')
->get();
but it has no result in o/p.
$data= users::leftJoin('orders', function($join) {
$join->on('orders.user_id', '=', 'users.id')
->on('orders.id', '=', DB::raw("(SELECT max(id) from orders WHERE orders.user_id = users.id)"));
})
->select(*)
This resolve my issue.
If you don't want to change anything in model you can go with this method as well, which is simple query builder method.
DB::table('orders')->leftJoin('users', 'orders.user_id', 'users.id')
->groupBy('orders.user_id')
->orderBy('orders.date', 'DESC')
->get();
Assuming, You might have "orders" function in User.php model
You can also go for below method. (Similar to the answer already given but for array of users instead of one user.)
$users = User::all();
foreach ($users as $user) {
$latest_order = $user->orders()->where('pay_type', 'xyz')->orderBy('date', 'DESC')->first(); // Option 1
$latest_order = $user->orders()->where('pay_type', 'xyz')->latest('date')->first(); // Option 2
}
You can use the following Relation in the User Model
public function latest_order(){
return $this->hasOne('Order')->orderBy('orders.date', 'desc')->limit(1);
}
Update
Since you can not change the Model, you can use the following code to fetch the latest Order for each User.
$user = User::first(); //get first User
$user->orders()->latest('date')->first();
I have a project where a user can create conversations with other users. A conversation can belongsToMany users and user can belongsToMany conversations.
I now need to get the conversation in which two specific users participate.
I tried a combination of solutions using whereIn and I tried the following:
$c = Conversation::whereHas('users', function($q)
{
$q->whereIn('user_id', array(1,3));
})
->get();
Here the problem is that whereIn('user_id', [1,3]) gets records that contains EITHER 1 or 3. I need it to return records that contains BOTH 1 and 3.
Conversation Model
class Conversation extends Model {
public function users(){
return $this->belongsToMany('App\User');
}
}
User Model
class User extends Model {
public function conversations(){
return $this->belongsToMany('App\Conversation');
}
}
Tables
conversations:
id | subject
conversation_user:
id | user_id | conversation_id
Data from table conversation_user
Your newest edit makes a lot more sense, this is actually a very easy fix. whereHas takes two additional parameters where it's going to look for the count.
$users = [1, 3];
$c = Conversation::whereHas('users', function($q) use ($users)
{
$q->whereIn('user_id', $users);
}, '>', count($users) )
->get();
This will get all conversations where user's 1 and 3 have participated in, even if there are additional users that have participated in those conversations. If you want only the conversations with only users 1 and 3, change the > to an =.
Edit: I just realized your pivot table has an id column. This method may not work if your pivot table is going to have duplicates. For example, if you have user_id of 1 in there twice with the same conversation_id both times, it will return that conversation even though it technically only has 1 user. I suggest removing the id column and creating a composite primary key of user_id and conversation_id. If there is the possibility of duplicates, it might be safer to use lukasgeiter's solution.
You are currently querying conversations which either user 1 and/or 3 takes part in. To achieve what you want you need two whereHas calls:
$c = Conversation::whereHas('users', function($q)
{
$q->where('user_id', 1);
})
->whereHas('users', function($q)
{
$q->where('user_id', 3);
}
->get();
And if you have more than two users, add them in a loop:
$users = [1, 2, 3, 4, 5];
$c = Conversation::query();
foreach($users as $userId){
$c->whereHas('users', function($q) use ($userId)
{
$q->where('user_id', $userId);
});
}
$c = $c->get();
I hope this will help you...
$userIds = array(1,3);
$c = Conversation::whereHas('users', function($q) use ($userIds)
{
$q->whereIn('user_id', $userIds);
})
->get();
I am using laravel to create a friend list. Now I want to get all of my friends with the name and avatar and stuff from the USER table.
My schema:
`cid`, `uid_by`, `uid_to`, `status`
uid_by (the inviting user)
uid_to (to be friend user)
status (accepted or ignored)
I only have 1 row per friendship. meaning its a 2 way friendship.
I tried to make a query:
$contacts = DB::table('contacts')
->leftJoin('users', 'contacts.uid_by', '=', 'users.uid')
->where('uid_by', $me)
->orWhere('uid_to', $me)
->where('contacts.status', 'accepted')
->get();
But its giving me some wrong information. Like instead of giving me the friend user info. its giving me my own info. All I want is to get the friends info.
Should I redesign the db? or am I missing something?
update
technically the thing is if uid_by is my user_id then check the uid_to else if the uid_by is not my user_id then check uid_by then use those to get the data from the users table uid column.
So my uid could be on uid_by and my friend on uid_to or vice versa.
But I can't get the query right.
See Advanced wheres:
$contacts = DB::table('contacts')
->join('users', 'contacts.uid_by', '=', 'users.uid')
->where('users.uid','<>',$me)
->where('contacts.status', 'accepted')
->where(function($query)
{
$query-->where('uid_by', $me)
->orWhere('uid_to', $me)
})
->get();