Mongoose嵌套对象数组中的唯一值

Gui*_*age 31 mongoose mongodb node.js

对于我的项目,我想为组织组保留一份mongoose文档,如下所示:

var groupSchema = Schema({
  name : { type : String },
  org : { type : Schema.Types.ObjectId, ref : 'Organization' },
  ...
  users : [{
    uid : { type : Schema.Types.ObjectId, ref : 'User' },
    ...
  }]
});
Run Code Online (Sandbox Code Playgroud)

我想阻止同一个用户在同一组中两次.为此,我需要强制users.uid在users数组中是唯一的.我尝试为uid说明'unique:true',但这不起作用.有没有办法用mongoose或mongoDB执行此操作而无需额外查询或拆分架构?

编辑:我将uid的先前值更改为uid:{type:Schema.Types.ObjectId,ref:'User',index:{unique:true,dropDups:true}}但是这似乎仍然不起作用.

编辑:假设没有简单的方法来实现这一点,我添加了一个额外的查询检查用户是否已经在组中.在我看来,这是最简单的方法.

Joh*_*yHK 82

在一个阵列场唯一索引强制执行相同的值不能出现在一个以上的阵列文档的集合中,但并不妨碍在单个文档的阵列多次出现相同的值.因此,您需要确保在向阵列添加元素时的唯一性.

$addToSet仅当值尚未存在时,才使用运算符向数组添加值.

Group.update({name: 'admin'}, {$addToSet: {users: userOid}}, ...
Run Code Online (Sandbox Code Playgroud)

但是,如果users数组包含具有多个属性的对象,并且您希望确保其中一个属性的唯一性(uid在本例中),则需要采用另一种方法:

var user = { uid: userOid, ... };
Group.update(
    {name: 'admin', 'users.uid': {$ne: user.uid}}, 
    {$push: {users: user}},
    function(err, numAffected) { ... });
Run Code Online (Sandbox Code Playgroud)

这样做的$push唯一条件是,只有user.uiduid任何元素的字段中不存在时才会发生更新users.所以它模仿$addToSet行为,但仅仅是uid.

  • 我们如何在第一次创建对象时使用验证或预保存挂钩来确保这一点? (3认同)

Ank*_*yan 9

好吧,这可能是个老问题,但是对于 mongoose > v4.1,您可以使用$addToSet运算符。

$addToSet 运算符将一个值添加到数组中,除非该值已经存在,在这种情况下 $addToSet 对该数组没有任何作用。

例子:

MyModal.update(
   { _id: 1 },
   { $addToSet: {letters: [ "c", "d" ] } }
)
Run Code Online (Sandbox Code Playgroud)

  • 除了 $addToSet 之外,还可以使用 $each 运算符将数组中的所有元素添加到数组中。{ $addToSet: { letters: { $each: [ "c", "d"] } } } 将完成所需的工作。谢谢 (6认同)
  • 我认为这不是一个很好的例子,因为这会将整个数组 `["c", "d"]` 作为一个元素附加到数组 `letters` 中,因此字母将是 `["a", "b", ["c", "d"]]` 请参阅 [mongodb 文档](https://docs.mongodb.com/manual/reference/operator/update/addToSet/) (2认同)