Я считаю, что вам нужно добавить coalese в свой отдельный on & order by, чтобы выбрать id
сообщения, когда parent_message_id
имеет значение null.
select("DISTINCT ON (parent_message_id) messages.*")
...
order("parent_message_id, created_at DESC")
необходимо преобразовать в
select("DISTINCT ON (COALESCE(parent_message_id, messages.id)) messages.*")
...
order("COALESCE(parent_message_id, messages.id), created_at DESC")
Итак, вы не предоставили образец таблиц базы данных и ожидаемое или полное определение модели, поэтому я делаю несколько выводов. Вот минимальные определения таблиц (как я их понял), необработанный запрос sql, который будет сгенерирован AR после предложенной мной модификации [это тот запрос, который нам нужен, учитывая схему ниже], и результаты.
Настройка
CREATE TABLE messages (
id int primary key
, parent_message_id int references messages(id)
, created_at timestamp default current_timestamp
);
INSERT INTO messages (id, parent_message_id) values
(1, NULL) -- parent message with children
, (2, 1)
, (3, 1)
, (4, NULL) -- parent message without children
, (5, NULL) -- another parent message without children
;
CREATE TABLE message_participants (
user_id int
, message_id int references messages(id)
)
INSERT INTO message_participants values (1, 1), (2, 2), (3, 3), (1, 4), (2, 5);
RAW SQL запрос, который дает нам последнее родительское или дочернее сообщение:
SELECT DISTINCT ON (COALESCE(parent_message_id, messages.id)) messages.*
FROM messages
JOIN message_participants ON message_participants.message_id = messages.id
WHERE message_participants.user_id = ? -- replace by user_id
ORDER BY COALESCE(parent_message_id, messages.id), created_at DESC
Результаты
Учитывая user_id = 1
, запрос выше возвращает результат:
id | parent_message_id | created_at
----+-------------------+----------------------------
1 | | 2020-05-11 13:50:00.857589
4 | | 2020-05-11 13:50:00.857589
(2 rows)
Учитывая user_id = 2
, приведенный выше запрос возвращает результат:
id | parent_message_id | created_at
----+-------------------+----------------------------
2 | 1 | 2020-05-11 13:50:00.857589
5 | | 2020-05-11 13:52:01.261975
(2 rows)
Сортировка общих результатов:
created_at DES C может получить последнее дочернее сообщение, но не сортирует всю коллекцию. Я могу решить эту проблему, вызвав .reverse, но мне интересно, есть ли способ исправить и это.
Чтобы выполнить сортировку в базе данных, вы можете обернуть вышеуказанный запрос в cte
пример:
WITH last_messages AS (
SELECT DISTINCT ON (COALESCE(parent_message_id, messages.id)) messages.*
FROM messages
JOIN message_participants ON message_participants.message_id = messages.id
WHERE message_participants.user_id = 2
ORDER BY COALESCE(parent_message_id, messages.id), created_at DESC
)
SELECT * FROM last_messages ORDER BY created_at;
Однако я не уверен на 100%, как это будет выражено в AR