【问题标题】:Laravel SubQuery Question, Get the most recent row when using whereInLaravel 子查询问题,使用 whereIn 时获取最新行
【发布时间】:2019-02-01 02:13:40
【问题描述】:

我有两张桌子:

线程

id, created_at, updated_at, deleted_at

消息

id, thread_id, user_id, created_at, updated_at, deleted_at

这是我创建的用于建立这种关系的 SQL Fiddle 的链接:

http://sqlfiddle.com/#!9/915829/3/0

线程模型对消息有这种关系

 /**
 * Messages relationship.
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 *
 * @codeCoverageIgnore
 */
public function messages()
{
    return $this->hasMany(Message::class, 'thread_id', 'id');
}

Message Model 对于 Thread 有这种关系:

 /**
 * Thread relationship.
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 *
 */
public function thread()
{
    return $this->belongsTo(Thread::class, 'thread_id', 'id');
}

我首先运行一个查询来获取特定用户的所有线程。获得所有线程后,我将每个线程的 id 提取到一个数组中。现在我想获取每个线程 ID 的最新消息。我试过这个:

Message::whereIn('thread_id', $threadIds)

但这给了我与每个 thread_id 相关的每条消息,看着这个我发现如果说一些线程有数千条与之相关的消息,这可能会导致一些重大问题。我还尝试了以下方法:

Message::whereIn('thread_id', $threadIds)->take(1)

它只返回一个我也不想要的结果。我想知道是否有人知道只为每个 $threadIds 获取最新消息的方法。

这是我的架构示例,其中包含一些示例数据:

CREATE TABLE `messages` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `thread_id` int(10) unsigned NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `body` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `threads` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `subject` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `threads` (`id`, `subject`, `created_at`, `updated_at`, `deleted_at`)
VALUES
    (1, 'test subject 1', '2019-02-01 00:32:56', '2019-02-01 00:32:56', NULL),
    (2, 'test subject 2', '2019-02-01 00:34:42', '2019-02-01 00:34:42', NULL);

INSERT INTO `messages` (`id`, `thread_id`, `user_id`, `body`, `created_at`, `updated_at`, `deleted_at`)
VALUES
    (1, 1, 2, 'test1', '2019-02-01 00:32:56', '2019-02-01 00:32:56', NULL),
    (2, 1, 1, 'test2', '2019-02-01 00:32:59', '2019-02-01 00:32:59', NULL),
    (3, 1, 2, 'test3', '2019-02-01 00:34:42', '2019-02-01 00:34:42', NULL),
    (4, 2, 1, 'test4', '2019-02-01 00:35:56', '2019-02-01 00:35:56', NULL),
    (5, 2, 3, 'test5', '2019-02-01 00:36:59', '2019-02-01 00:36:59', NULL),
    (6, 2, 1, 'test6', '2019-02-01 00:37:42', '2019-02-01 00:37:42', NULL);

假设我想获取 id 为 1 和 2 的线程的最新消息,我想要这样的结果集:

id  thread_id   user_id body    created_at  updated_at  deleted_at
3   1   2   test3   2019-02-01T00:34:42Z    2019-02-01T00:34:42Z    (null)
6   2   1   test6   2019-02-01T00:37:42Z    2019-02-01T00:37:42Z    (null)

我在网上查找了类似的问题,并在堆栈溢出here 上找到了一个非常相似的问题,但不幸的是没有得到答复。提前感谢任何试图回答这个问题的人。

【问题讨论】:

  • 线程和消息的关系是什么?在 Model 中有你的集合 hasMany 或 belongsTo? laravel.com/docs/5.7/eloquent-relationships
  • @LimKeanPhang ,是的,模型中的关系是 hasMany 和 belongsTo,我已经更新了我的问题以显示模型中的关系。
  • @Strawberry 我相信我正在关注你的所有 3 件很高兴看到的事情,我解释了我有 Message::whereIn('thread_id', $threadIds) 的工作查询,我正在寻求帮助来改进它。
  • @Strawberry 很抱歉造成混淆,我已经添加了一个指向我刚刚创建的 SQL 小提琴的链接,它构建了 2 个表,添加了一些示例数据,并且我添加了我目前正在使用的 SQL 语句使用。感谢您的信息,这是我第一次在 SO 上发布 PHP / SQL 问题。
  • sqlfiddle.com/#!9/915829/5 - 请注意,您的第一个查询可能是不必要的。查看联接

标签: php mysql laravel eloquent


【解决方案1】:

我不确定这是否是最佳方法。但我试过了,它奏效了。

我的方法是在获取 threadIds 数组后,运行一个循环并获取每个线程的最新消息。然后我将该消息存储在另一个数组中。

$messages = array();
foreach($threadIds as $threadId)
{
    $message = Message::where('thread_id', $threadId)
               ->whereNotNull(`deleted_at`)
               ->orderby('created_at','desc')
               ->first();

    $messages[] = $message;
}
dd($messages);

【讨论】:

  • 感谢您的意见,但我不能将此标记为正确答案,就像您说的那样,这绝对不是最佳方法。如果我有 100 个 threadId,我最终会调用 100 次数据库调用来获取每条消息。
猜你喜欢
  • 1970-01-01
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2017-04-13
  • 2021-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多