将用户与过滤器配对

时间:2014-08-06 10:31:55

标签: sql postgresql redis subquery

我正在尝试配对在不同时间宣布自己的用户。以下是我目前正在做的伪代码

这是我的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数据库。

1 个答案:

答案 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来明确随机化。