Php 获取Laravel中每个用户的最新消息(行)
TL;DR:需要每个发件人的最新消息 在我的Laravel应用程序中,我有两个表: 用户:Php 获取Laravel中每个用户的最新消息(行),php,laravel,Php,Laravel,TL;DR:需要每个发件人的最新消息 在我的Laravel应用程序中,我有两个表: 用户: 身份证 名字 信息: 身份证 发送者身份证 收件人id 身体 创建于 当然还有模型 用户模型: public function messages() { return $this->hasMany('App\Message', 'recipient_id'); } public function messages() { return $this->hasMany(M
- 身份证
- 名字
- 身份证
- 发送者身份证
- 收件人id
- 身体
- 创建于
public function messages() {
return $this->hasMany('App\Message', 'recipient_id');
}
public function messages() {
return $this->hasMany(Message::class, 'recipient_id');
}
public function latestMessagePerSender()
{
return $this->messages()
->whereNotExists(function ($query) {
$query->from('messages AS m2')
->whereRaw('m2.sender_id = messages.sender_id')
->whereRaw('m2.created_at > messages.created_at');
});
}
消息模型:
public function sender() {
return $this->belongsTo('App\User', 'sender_id');
}
public function recipient() {
return $this->belongsTo('App\User', 'recipient_id');
}
当用户打开收件箱时,他应该会看到来自任何其他用户的最新消息列表
因此,如果有消息:
id sender_id recipient_id body created_at
1, 2, 1, hi, 2016-06-20 12:00:00
2, 2, 1, hi, 2016-06-21 12:00:00
3, 3, 1, hi, 2016-06-20 12:00:00
4, 3, 1, hi, 2016-06-21 12:00:00
那么id为1(收件人id)的用户应该只看到id为2和4的邮件
这是用户模型中的当前解决方案:
return Message::whereIn('id', function($query) {
$query->selectRaw('max(`id`)')
->from('messages')
->where('recipient_id', '=', $this->id)
->groupBy('sender_id');
})->select('sender_id', 'body', 'created_at')
->orderBy('created_at', 'desc')
->get();
这是可行的,但我想知道是否有可能通过拉雷维尔的方式实现这一点。可能是迫不及待地装载。我的拉威尔技巧还不够,经过几天的尝试,我没有找到解决办法
谢谢。为什么不像这样简单地访问
消息呢-
// get the authenticated user
$user = \Auth::user();
// find the messages for that user
return User::with('message')->find($user->id)->messages;
你可以试试这个
Messages::where('recipient_id',**{USER_ID}**)
->group_by('sender_id')
->order_by('id','desc')
->get();
从中汲取灵感,最有效的方法是:
DB::table('messages AS m1')
->leftjoin('messages AS m2', function($join) {
$join->on('m1.sender_id', '=', 'm2.sender_id');
$join->on('m1.id', '<', 'm2.id')
})->whereNull('m2.id')
->select('m1.sender_id', 'm1.body', 'm1.created_at')
->orderBy('m1.created_at', 'm1.desc')->get();
DB::table('messages AS m1')
->leftjoin('消息为m2',函数($join){
$join->on('m1.sender_id','=','m2.sender_id');
$join->on('m1.id','这可能是一个解决方案(但未测试)
这是我发现的最“雄辩的方式”:
在用户模型中:
public function messages() {
return $this->hasMany('App\Message', 'recipient_id');
}
public function messages() {
return $this->hasMany(Message::class, 'recipient_id');
}
public function latestMessagePerSender()
{
return $this->messages()
->whereNotExists(function ($query) {
$query->from('messages AS m2')
->whereRaw('m2.sender_id = messages.sender_id')
->whereRaw('m2.created_at > messages.created_at');
});
}
然后只需$user->latestMessagePerSender
也许您可以试试这个:
$user = \Auth::user();
// Get the latest date
$last_date_created = Message::latest()->first()->created_at; // also check for possible null
// Get the date only - use to specify date range in the where section in the eloquent query
$target_date = date('Y-m-d', strtotime( $last_date_created ) );
// Retrieve the messages
$latest_posts = Message::where('recipient_id', $user->id)
->where('created_at', '>=', $target_date . ' 00:00:00')
->where('created_at', '<=', $target_date . ' 23:59:59')
->groupBy('sender_id')
->groupBy('created_at')
->get();
return $latest_posts;
$user=\Auth::user();
//获取最新日期
$last_date_created=Message::latest()->first()->created_at;//还要检查可能的空值
//仅获取日期-用于在雄辩查询的where部分中指定日期范围
$target_date=date('Y-m-d',strottime($last_date_created));
//检索消息
$latest\u posts=Message::where('recipient\u id',$user->id)
->其中('created_at','>=',$target_date.'00:00:00')
->在哪里('created_at',“我尝试了一些类似的方法,发现你只需要在找到用户的所有消息后立即按created_at
排序,然后你就可以使用Laravel的集合
按发件人id
对它们进行分组。因此,据我所知,以下方法应该有效,即给你用户从发件人s接收的最后一条消息:
因此,假设您有一个经过身份验证的用户
作为$User
,在此上下文中,该用户与消息
表中具有接收方id的接收方
相同,那么:
$messages = $user->messages()
->orderBy('created_at', 'desc')
->get(['sender_id', 'body', 'created_at'])
->groupBy('sender_id'); //this is collections method
然后循环收集,并获取第一个:
$result = new \Illuminate\Database\Eloquent\Collection ();
foreach ($messages as $message){
$result->push($message->first()); //the first model in the collection is the latest message
}
您应该得到如下结果:
Illuminate\Database\Eloquent\Collection {#875
all: [
App\Message {#872
sender_id: "2",
body: "hi",
created_at: "2016-06-21 12:00:00",
},
App\Message {#873
sender_id: "4",
body: "hi",
created_at: "2016-06-21 12:00:00",
},
]
PS:需要注意的是,我不能说这可能有多高效,但有一点是肯定的,那就是数据库上的查询数量有限
希望有帮助:)
更新:
我试着把它拆了~
它将属于用户的消息
的所有记录提取到一个集合中(已由created_at排序),然后使用该文档中给出的结果
这次我没有转换为数组。相反,它是集合的集合。比如集合(集合(消息))
然后在每个索引中选择第一个模型。我已经传递到get()
方法中的参数确保只存在这些字段(即->get(['sender\u id','body','created\u at'])
。这与mysql groupBy()完全不同,因为它不会为每个组返回一行,而只是根据给定的标识符对所有记录进行分组
另一次更新
我后来发现,对生成的有序消息调用unique()
方法实际上可以完成这项工作,但在这种情况下,唯一标识符将是sender\u id
(ref:),即:
结果是,我们不需要foreach的和groupBy,我们在这里得到了结果
另一种避免重复(上述内容)的方法是,如果需要在多个地方使用,即在<代码>消息代码>模型中,我们可以使用以下内容:
public function scopeLatestSendersMessages($query)
{
return $query->orderBy('created_at', 'desc')
->get(['sender_id', 'body', 'created_at'])
->unique('sender_id');
}
然后在控制器中使用:
$messages = $user->messages()->latestSendersMessages();
PS:仍然不确定哪一个比另一个更好。我喜欢前面提到的更简单的方法
在您的用户
模型中,除了现有的消息()
关系之外,还要添加此关系
public function latestMessage()
{
return $this->hasOne(Message::class, 'recipient_id')->latest();
}
然后,当您查询时,只需像这样进行查询
$messages = User::with('latestMessage')->get();
$messages = User::with(['latestMessage' => function($message) {
$message->orderBy('id', 'desc');
}])->get();
$messages
包含每个用户的最新消息
编辑
为了按datetime/id对结果进行排序,您可以这样做
$messages = User::with('latestMessage')->get();
$messages = User::with(['latestMessage' => function($message) {
$message->orderBy('id', 'desc');
}])->get();
$messages
包含由id
订购的每个用户的最新消息。我在另一个论坛中找到了此解决方案,我想这就是您要寻找的。我发布此解决方案是为了对其他用户有用
DB::select('
SELECT t1.*
FROM messages AS t1
INNER JOIN
(
SELECT
LEAST(sender_id, recipient_id) AS user_id,
GREATEST(sender_id, recipient_id) AS recipient_id,
MAX(id) AS max_id
FROM messages
GROUP BY
LEAST(sender_id, recipient_id),
GREATEST(sender_id, recipient_id)
) AS t2
ON LEAST(t1.sender_id, t1.recipient_id) = t2.sender_id AND
GREATEST(t1.sender_id, t1.recipient_id) = t2.recipient_id AND
t1.id = t2.max_id
WHERE t1.sender_id = ? OR t1.recipient_id = ?
', [auth()->guard('api')->user()->id, auth()->guard('api')->user()->id]);
原始帖子:因为它将返回用户收到的所有邮件。但我只需要每个发件人的最新邮件。好的,你之前的问题不太清楚。无论如何,如果你想这样做,另一个解决方案可能是保留“正在阅读”在您的消息表中标记,默认值为N
。稍后,一旦消息被读取,您可以将其更新为Y
。这样,您只能筛选is_read='N'
记录,并避免使用max()
查询。实际上我有此标记(问题简化)。但是,这仍然没有用。如果用户从其他几个用户那里收到多条新消息,他们都会有此标志(未读取)。因此,基本上这是相同的问题,只是结果中有另一列。您的答案仍然返回所有消息。您所做的是“为第一个用户获取所有消息”,这与“获取每个用户的最新消息”我认为这个解决方案是完全好的。这个解决方案是什么