Reputation: 2516
I have n users in a table and for each user, I'm saving their log-in and log-out time in a separate table. I want to get the details of the users who haven't logged-in for 2 days using Laravel eloquent.
Users table structure
id | name | email
Log table structure
id |action | user_id | created_at | updated_at
So far I have done this much:
$users = LogsData::where('action','Login')->where('created_at','<',Carbon::now()->subDays(1))->get();
But the output has users who have logged-in within 2 days also.
EDIT: I got the query, I need to convert this into eloquent.
I solved it myself. Here is the solution:
SELECT t1.* FROM actions t1
JOIN (SELECT user_id, MAX(id) as maxid FROM actions where action = "LOGIN" GROUP BY user_id) t2
ON t1.user_id = t2.user_id and t1.id = t2.maxid
where created_at < NOW() - INTERVAL 2 DAY
Upvotes: 0
Views: 3874
Reputation: 1706
If you only need to get the last data of each user, you can sort the id
desc and then group by user_id
to get the latest data
$users = LogsData::where('action','Login')
->whereDate('created_at','<',Carbon::today()->subDays(1))
->orderBy('id', 'DESC')
->groupBy('user_id')
->get();
to use groupBy
, you have to change the strict
from your config value into false
. But if you don't want to change your config file, this query can help you. You just need to translate it into laravel query version
SELECT * FROM log_datas AS ld WHERE ld.action = 'Login' AND ld.id IN (SELECT MAX(id) FROM log_datas WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 DAY) GROUP_BY user_id)
Upvotes: 1
Reputation: 856
Maybe try using eloquent relations
Take note of your namespaces make sure that App\LogsData for example is correct here
// in your User Model
public function logsData()
{
return $this->hasMany('App\LogsData');
}
// in your LogsData Model
public function user()
{
return $this->belongsTo('App\User');
}
public function scopeLoginActions($query)
{
return $query->where('action', 'Login');
}
Then you can access data with
User::whereHas('logsData', function ($query) {
$query->loginActions()->where('created_at', '<', now()->subDays(2));
})->get();
// and if you require the login records
User::with('logsData')->whereHas('logsData', function ($query) {
$query->loginActions()->where('created_at', '<', now()->subDays(2));
})->get();
// and if you require an individual login record
User::with(['logsData' => function($query) {
$query->loginActions()->where('created_at', '<', now()->subDays(2))->first();
})->whereHas('logsData', function ($query) {
$query->loginActions()->where('created_at', '<', now()->subDays(2));
})->get();
Upvotes: 0
Reputation: 7585
You need to make a join to the logs table first, and because MySQL always seeks the path of least resistance, you need to join it the other way around: there may not exists log entries YOUNGER than 1 day.
$users = DB::from('users')
->leftJoin('logs', function ($join) {
$join->on('users.id', '=', 'logs.user_id')
->where('logs.action', '=', 'Login')
->where('logs.created_at', '>=', Carbon::now()->subDays(2));
})
->whereNull('logs.id')
->get();
Upvotes: 0