MongoDB:双面唯一键约束

时间:2014-01-08 22:36:21

标签: mongodb database-design database

问题:我正在mongo中创建一个friend_requests集合,我想在两个用户ID之间强制执行一个唯一的密钥(假设我有一个“from_user”和“to_user” “键/列)。然而,经过测试,我发现唯一性只能在一个方向上实施。

当前“架构”

这是我的索引:

> db.friend_requests.getIndexes();
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "ns" : "myapp.friend_requests",
        "name" : "_id_"
    },
    {
        "v" : 1,
        "key" : {
            "from_user" : 1,
            "to_user" : 1
        },
        "unique" : true,
        "ns" : "myapp.friend_requests",
        "name" : "from_user_1_to_user_1"
    }
]

这是我的数据证明唯一性是单向的:

> db.friend_requests.find();
{ "_id" : ObjectId("52cd715dcf75451e70450f6e"), "from_user" : "a", "to_user" : "b" }
{ "_id" : ObjectId("52cd741cddf3114c4c501d19"), "from_user" : "b", "to_user" : "a" }

解决方案

首选解决方案不依赖于管理代码来检查唯一性,但是如果我正确,则无法告诉mongo在内部执行此操作。所以我想下一个最好的事情是尽可能轻量级的管理代码。

我发现mysql实现的一个轻量级解决方案是你总是将最低的密钥存储在第一列中(即我的示例中的“from_user”,但如果我显然实现了这个想法,我称之为“user1”),只要您始终以该格式插入新数据,唯一键约束将始终在需要时触发。这种实现方法的好处是,当查找两个用户之间的现有请求时,您不必查找两个变量(即,不必检查1,2或2,1,因为它应该始终只是1,2如果记录存在)。

显然,该解决方案基于mysql具有递增整数id的想法。 Mongo id不是整数,所以我假设没有真正“较小”的id?

脚注:我对mongo完全不熟悉,所以我可能会犯一些严重愚蠢的数据库设计错误。

提前感谢任何建议。

2 个答案:

答案 0 :(得分:0)

如果您可以索引值,则必须为well-ordered,因此您可以比较任意两个可索引键,即使它们属于ObjectIdUUID等类型,因此始终将较低值存储在特定字段中的方法。

然而,确保比较一致地实施是很重要的。例如,比较可能会转换为字符串并比较字符串。或者,人们可能会选择直接比较字节,这会在小端和大端机器上产生不同的结果。

答案 1 :(得分:0)

你提出的解决方案是合理的。使用以下架构创建文档,并确保应用程序始终将最低用户ID放在user1字段中。

{
    user1: "a",
    user2: "b",
    ...
}

然后,在{ user1 : 1, user2 : 1 }上创建unique compound索引,以强制执行所需的唯一性约束。

或者,如果您想要维护有关哪个用户发起好友请求的信息,请考虑添加第三个字段以强制执行唯一性。使用以下架构创建文档:

{
    from_user : "a",
    to_user : "b",
    req_key : "ab",
    ...
}

应用程序可以连接两个用户ID并存储在req_key字段中,确保最低的用户ID首先出现。然后,在{ req_key : 1 }上添加唯一索引。