我很难找到一种方法让收集索引以我需要的方式工作。该集合有一个包含两个元素的数组,没有其他数组可以包含这两个元素(按任意顺序):
db.collection.insert(users : [1,2] // should be valid
db.collection.insert(users : [2,3] // should be valid
db.collection.insert(users : [1,3] // should be valid
db.collection.insert(users : [3,2] // should be invalid, since there's another array with that same value.
但是,如果我使用db.collection.createIndex({users:1}, {unique: true})
,它将不允许我有两个带有公共元素的数组:
db.collection.insert(users : [1,2] // valid
db.collection.insert(users : [2,3] // invalid, since 2 is already on another document
我尝试的解决方案之一是使阵列更深一层。创建完全相同的索引,但添加稍微不同的文档会使它几乎成为我需要的方式,但它仍然允许两个数组在相反的顺序中具有相同的值:
db.chat.insert({ users : { people : [1,2] }}) // valid
db.chat.insert({ users : { people : [2,3] }}) // valid
db.chat.insert({ users : { people : [2,1] }}) // valid, but it should be invalid, since there's another document with [1,2] array value.
db.chat.insert({ users : { people : [1,2] }}) // invalid
有没有办法在索引级别实现这一目标?
答案 0 :(得分:1)
mongodb 不会在整个阵列上创建索引。但...
我们想要一个原子操作insert
或update
,并保证数组内容的唯一性?然后,我们需要为数组项的所有排列计算一个 ,并为其创建唯一索引。
一种方法是对数组项进行排序(解决排列问题)并将它们连接起来(创建一个特征)。该示例位于javascript
:
function index(arr) {
return arr.sort().join();
}
users1 = [1, 2], usersIndex1 = index(users1); // "1,2"
users2 = [2, 1], usersIndex2 = index(users2); // "1,2"
// Create the index
db.collection.ensureIndex({usersIndex: 1}, {unique: true});
//
db.collection.insert({users: users1, usersIndex: usersIndex1}); // Ok
db.collection.insert({users: users2, usersIndex: usersIndex2}); // Error
如果数组很长,您可以对字符串应用散列函数,从而最小化集合的大小。但是,它带来了可能发生碰撞的代价。
答案 1 :(得分:0)
您必须在pre save hook
:
chatSchema.pre('save', (next) ->
data = @
@.constructor.findOne {}, (err, doc) ->
return next err if err?
return next "Duplicate" if customValidation(data, doc) == false
return next()
)
customValidation = (oldDoc, newDoc)->
#whatever you need
e.g. return !lodash.equal(oldDoc, newDoc)
var customValidation;
chatSchema.pre('save', function(next) {
var data;
data = this;
return this.constructor.findOne({}, function(err, doc) {
if (err != null) {
return next(err);
}
if (customValidation(data, doc) === false) {
return next("Duplicate");
}
return next();
});
});
customValidation = function(oldDoc, newDoc) {
return !lodash.equal(oldDoc, newDoc);
};
答案 2 :(得分:0)
您应首先找到记录,如果没有可用记录,则插入
db.chat.findOne({users: {$all: [3,2]}})
.then(function(doc){
if(doc){
return res.json('already exists');
} else {
db.chat.insert({users: [3,2]})
}
})
.catch(next);