节点使用 ObjectionJS 和 Knex,1 到多,return 来自许多 table 的第一个相关行
Node use ObjectionJS and Knex, 1 to many, return first related row from the many table
为了简单起见,我有两个用于聊天框的表格:Conversation
和 Message
对话
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)
为了简单起见,我有两个用于聊天框的表格:Conversation
和 Message
对话
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)