Reputation: 126487
In my app, users
CREATE TABLE users (
id bigserial PRIMARY KEY,
username varchar(50) NOT NULL
);
can send messages
CREATE TABLE messages (
id bigserial PRIMARY KEY,
from_id bigint NOT NULL REFERENCES users ON DELETE RESTRICT,
body text NOT NULL CHECK (body <> ''),
created_at timestamp(0) NOT NULL DEFAULT LOCALTIMESTAMP(0)
);
to many recipients
CREATE TABLE message_recipients (
message_id bigint NOT NULL REFERENCES messages ON DELETE CASCADE,
user_id bigint NOT NULL REFERENCES users ON DELETE RESTRICT,
PRIMARY KEY (message_id, user_id)
);
See this SQL Fiddle.
How do I SELECT
the (e.g., 20) latest messages between a group of users?
E.g., how do I get the 20 latest messages between users 1, 2, and 3? I.e., how do I get the messages limited to the latest 20 that 1 has sent to both 2 & 3, 2 has sent to both 1 & 3, and 3 has sent to both 1 & 2?
NOTE: I don't want to assign the messages to channels. I want to filter them by senders & receivers.
Related Question: Get a subset of messages between specific users
Upvotes: 0
Views: 41
Reputation: 7286
First aggregate the participants for each message, then you can match the participant list.
WITH target_group (members) AS (
VALUES (ARRAY [1, 2, 3] :: BIGINT [])
), message_group AS (
SELECT
-- message id
m.id,
-- aggregate the ids of all message parties
array_agg(mr.user_id) || m.from_id AS members
FROM message_recipients mr
JOIN messages m ON m.id = mr.message_id
JOIN target_group tg ON tg.members @> ARRAY [m.from_id]
GROUP BY m.id
)
SELECT
m.id,
m.body
FROM message_group mg
JOIN messages m ON m.id = mg.id
JOIN target_group tg ON tg.members @> mg.members AND array_length(tg.members, 1) = array_length(mg.members, 1)
ORDER BY m.id DESC
LIMIT 20;
Upvotes: 1