我正在尝试配对在不同时间宣布自己的用户。以下是我目前正在做的伪代码:
这是我的attempts
表:
CREATE TABLE attempts (
id integer PRIMARY KEY autoincrement,
user_id integer NOT NULL,
target_id integer NOT NULL,
status smallint NOT NULL,
);
逻辑:
// Try to match someone that is available
// - $match = UPDATE attempts set status = STATUS_MATCHED, target_id = [my user id] where status = STATUS_AVAILABLE limit 1;
// If you didn't find anyone then announce yourself
// - $row_id = INSERT into attempts values (null, [my user id], null, STATUS_AVAILABLE);
// wait a bit of time
// Disable your announcement
// - UPDATE $row set STATUS_FORFEIT if status = STATUS_AVAILABLE
// Grab your row again and see if you matched someone or if you are a forfeit
// - SELECT status,target_id from attempts where id = $row_id;
这很有效,人们可以匹配。但我们有一个功能,你可以阻止某些人。所以现在我需要检查一个被阻止的列表,这样你就不会匹配阻止你的人或者你已经阻止的人(两个方向)。
CREATE TABLE blocked (
id integer PRIMARY KEY autoincrement,
user_id integer NOT NULL,
target_id integer NOT NULL,
active boolean NOT NULL,
);
那么解决这个问题的最佳方法是什么?我唯一能想到的是一个子选择你正在做的事情:
UPDATE attempts
SET status = STATUS_MATCHED, target_id = [my user id]
WHERE status = STATUS_AVAILABLE
AND (
//and Where the following query return 0 rows
//SELECT FROM blocked where user_id in ([my user id], attempts.user_id)
// AND target_id in ([my user id], attempts.user_id)
// AND active = true
)
LIMIT 1;
如果改变了事情,使用postgresql。如果这种类型的操作更适合那里的东西,我也有一个redis数据库。
答案 0 :(得分:1)
这是你在找什么?
UPDATE a
SET status = STATUS_MATCHED,
target_id = [my user id]
FROM attempts a
WHERE a.id in (SELECT id
FROM attempts a2
WHERE a2.status = STATUS_AVAILABLE AND
NOT EXISTS (SELECT 1
FROM blocked b
WHERE b.user_id in ([my user id], a2.user_id) AND
b.target_id in ([my user id], a2.user_id) AND
b.active = true
)
LIMIT 1
);
Postgres的难点在于limit
中实现update
逻辑。这样做使用子查询与主键进行比较。请注意,更新任意匹配行。您可能希望通过在order by random()
之前添加limit 1
来明确随机化。