Mongodb Mongo中的唯一数组值

Mongodb Mongo中的唯一数组值,mongodb,indexing,unique,Mongodb,Indexing,Unique,我很难找到一种方法使集合索引按我需要的方式工作。该集合有一个包含两个元素的数组,任何其他数组都不能包含这两个元素(以任何顺序): 但是,如果我使用db.collection.createIndex({users:1},{unique:true}),它将不允许使用两个具有公共元素的数组: db.collection.insert(users : [1,2] // valid db.collection.insert(users : [2,3] // invalid, since 2 is alre

我很难找到一种方法使集合索引按我需要的方式工作。该集合有一个包含两个元素的数组,任何其他数组都不能包含这两个元素(以任何顺序):

但是,如果我使用
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

有没有办法在索引级别实现这一点?

您必须在
预保存挂钩中编写自定义验证:

咖啡版 预存钩 自定义验证 Js版本
您应该首先找到记录,如果没有可用的记录,则插入该记录

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);

mongodb不会在整个数组上创建索引。但是

我们需要一个原子操作
插入
更新
,并保证数组内容的唯一性?然后,我们需要为数组项的所有排列计算一个相同的特征,并为其创建一个唯一索引

一种方法是对数组项进行排序(解决排列问题)并连接它们(创建一个特征)。例如,在
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
如果数组很长,可以对字符串应用哈希函数,从而最小化集合的大小。尽管如此,它还是要付出可能发生碰撞的代价

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);
};
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);
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