说我有a
和b
字段。我想拥有一个复合唯一性,如果a: 1, b: 2
,我将无法做a: 2, b: 1
。
我想要这样做的原因是因为我正在创建“朋友列表”类型的集合,如果a
连接到b
,那么它也将自动反向。
这是在模式级别上实现的吗?还是我需要执行查询以进行检查。
答案 0 :(得分:1)
如果您不需要区分请求者和被请求者,则可以在保存或查询之前对值进行排序,以使两个a
和b
字段对任何一对朋友具有可预测的顺序ID(并且您可以利用唯一索引约束)。
例如,使用mongo
shell:
创建一个帮助函数,以可预测的顺序返回朋友对:
function friendpair (friend1, friend2) {
if ( friend1 < friend2) {
return ({a: friend1, b: friend2})
} else {
return ({a: friend2, b: friend1})
}
}
添加复合唯一索引:
> db.friends.createIndex({a:1, b:1}, {unique: true});
{
"createdCollectionAutomatically" : true,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
插入唯一对(应该起作用)
> db.friends.insert(friendpair(1,2))
WriteResult({ "nInserted" : 1 })
> db.friends.insert(friendpair(1,3))
WriteResult({ "nInserted" : 1 })
插入非唯一对(应返回重复的密钥错误):
> db.friends.insert(friendpair(2,1))
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.friends index: a_1_b_1 dup key: { : 1.0, : 2.0 }"
}
})
搜索应按以下两种顺序进行:
db.friends.find(friendpair(3,1)).pretty()
{ "_id" : ObjectId("5bc80ed11466009f3b56fa52"), "a" : 1, "b" : 3 }
db.friends.find(friendpair(1,3)).pretty()
{ "_id" : ObjectId("5bc80ed11466009f3b56fa52"), "a" : 1, "b" : 3 }
您也可以将findAndModify
与upsert
一起使用,而不是处理重复的键错误或插入与更新,因为这应该是唯一的对:
> var pair = friendpair(2,1)
> db.friends.findAndModify({
query: pair,
update: {
$set: {
a : pair.a,
b : pair.b
},
$setOnInsert: { status: 'pending' },
},
upsert: true
})
{
"_id" : ObjectId("5bc81722ce51da0e4118c92f"),
"a" : 1,
"b" : 2,
"status" : "pending"
}
答案 1 :(得分:0)
您似乎无法对整个数组的值进行唯一处理,因此我正在做一种变通方法。我正在使用Launch agent via Java Web Start
,如下所示:
$jsonSchema
然后,我将使用{
$jsonSchema:
{
bsonType:
"object",
required:
[
"status",
"users"
],
properties:
{
status:
{
enum:
[
"pending",
"accepted"
],
bsonType:
"string"
},
users:
{
bsonType:
"array",
description:
"references two user_id",
items:
{
bsonType:
"objectId"
},
maxItems:
2,
minItems:
2,
},
}
}
}
查找已连接的用户,例如
$all