问题:我正在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完全不熟悉,所以我可能会犯一些严重愚蠢的数据库设计错误。
提前感谢任何建议。
答案 0 :(得分:0)
如果您可以索引值,则必须为well-ordered,因此您可以比较任意两个可索引键,即使它们属于ObjectId
,UUID
等类型,因此始终将较低值存储在特定字段中的方法。
然而,确保比较一致地实施是很重要的。例如,比较可能会转换为字符串并比较字符串。或者,人们可能会选择直接比较字节,这会在小端和大端机器上产生不同的结果。
答案 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 }
上添加唯一索引。