节点使用 ObjectionJS 和 Knex,1 到多,return 来自许多 table 的第一个相关行

Node use ObjectionJS and Knex, 1 to many, return first related row from the many table

为了简单起见,我有两个用于聊天框的表格:ConversationMessage

对话

id status
1 open
2 open

留言

idConversation text date
1 'ffff' (random date)
1 'asdf' (random date)
1 '3123123123' (random date)
2 'asdfasdff' (random date)
2 'asdfasdfcas' (random date)
2 'asdfasdfasdf' (random date)

我可以 select 所有 Conversation 很容易,方法是:

await Conversation.query().where({
    status: 'open',
  })

但我正在尝试将这些连接到一个查询中,以便每次对话获得 1 条消息。这是我现在的查询:

await Conversation.query()
    .where({
      status: 'open',
    })
    .innerJoin('Message', 'Message.idConversation', 'Conversation.id')
    .distinct('Message.idConversation')
    .select('Message.idConversation', 'Message.text')

但这会产生如下结果:

  [ 
    {
     idConversation: 1,
     text: 'ffff'
    },
    {
     idConversation: 1,
     text: 'asdf'
    },
    {
     idConversation: 1,
     text: '3123123123'
    },
     ....
  ]

我只想为每个对话 ID 发送一条消息,例如:

    {
     idConversation: 1,
     text: 'ffff'
    },
    {
     idConversation: 2,
     text: 'asdfasdff'
    },

我该如何解决这个问题?

这是原始的:

    SELECT u.id, p.text
    FROM Conversation AS u
    INNER JOIN Message AS p ON p.id = (
      SELECT id
    FROM Message AS p2
    WHERE p2.idConversation = u.id
    LIMIT 1
  )

您正在尝试解决“每组最大值”问题。

一种方法是通过相关子查询,即 "select 日期等于(此会话中所有消息的最新日期)的消息" .只要您的应用程序保证同一对话中的两条消息不能具有相同的日期,此方法就有效。

在knex这个

knex({c: 'Conversation'})
    .innerJoin({m: 'Message'}, 'm.idConversation', 'c.id')
    .where({
      'c.status': 'open',
      'm.date': knex('message')
        .where('idConversation', '=', knex.raw('c.id'))
        .max('date')
    })
    .select('m.idConversation', 'm.text')

结果 SQL 像这样(注意 table 别名)

select
  m.idConversation,
  m.text
from
  Conversation as c
  inner join Message as m on m.idConversation = c.id
where
  c.status = 'open'
  and m.date = (select max(date) from message where idConversation = c.id)