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

62

对于我的项目,我想要为组织团体保留mongoose文档,就像这样:

var groupSchema = Schema({
  name : { type : String },
  org : { type : Schema.Types.ObjectId, ref : 'Organization' },
  ...
  users : [{
    uid : { type : Schema.Types.ObjectId, ref : 'User' },
    ...
  }]
});
我想防止同一用户在同一个组中出现两次。为此,我需要强制 users.uid 在用户数组中是唯一的。我尝试为 uid 声明 'unique: true',但这并没有起作用。是否有一种方法可以在 mongoose 或 mongoDB 中实现这一点,而无需额外的查询或拆分模式?
编辑: 我更改了先前的 uid 值为 uid:{type:Schema.Types.ObjectId,ref:'User',index:{unique:true,dropDups:true}} 但这似乎仍然不起作用。
编辑:假设没有简单的方法来实现这一点,我添加了一个额外的查询,检查用户是否已经在该组中。这对我来说似乎是最简单的方法。

请查看此链接,它会很有帮助:https://dev59.com/DGjWa4cB1Zd3GeqPp2Ha - karthick
谢谢提供链接。我尝试了以下代码: uid : { type : Schema.Types.ObjectId, ref : 'User', index: {unique: true, dropDups: true} } 替换了旧的uid值。但这仍然无法解决问题,我也尝试重新启动mongoDB,但没有成功。 - Guido Passage
2个回答

148

在数组字段上创建唯一索引可以确保集合中的多个文档的数组中不会出现相同值,但是无法阻止单个文档的数组中出现相同值。因此,您需要在向数组添加元素时确保其唯一性。

使用$addToSet操作符仅在该值不存在时将其添加到数组中。

Group.updateOne({name: 'admin'}, {$addToSet: {users: userOid}}, ...

然而,如果users数组包含多个属性的对象,并且您希望仅确保其中一个属性(在此情况下为uid)的唯一性,则需要采取另一种方法:

var user = { uid: userOid, ... };
Group.updateOne(
    {name: 'admin', 'users.uid': {$ne: user.uid}}, 
    {$push: {users: user}},
    function(err, numAffected) { ... });

这样做的作用是限定$push更新仅在user.uid不存在于users的任何元素的uid字段中时发生。因此,它模仿了$addToSet的行为,但只针对uid


但是你如何强制仅 uid 是唯一的?在用户数组中,我有更多的属性,每次添加相同的用户时可能会不同(例如日期)。 - Guido Passage
6
我们如何确保在创建对象时首次使用验证或预保存钩子? - Anubhav Singh
1
如果要添加多个用户,这种方法会如何工作?所以需要一个对象数组吗?谢谢。 - Miguel Stevens
当字段的模式类型为数组时,$addToSet是否起作用? - Kay
1
尝试添加具有重复ID的用户时,这不会引发错误。 - Ranjan
显示剩余6条评论

16

虽然这可能是一个旧问题,但对于mongoose>v4.1,您可以使用$addToSet操作符。

$addToSet操作符将一个值添加到数组中,除非该值已经存在,在这种情况下,$addToSet不会对该数组进行任何操作。

例如:

MyModal.update(
   { _id: 1 },
   { $addToSet: {letters: [ "c", "d" ] } }
)

2
我认为这不是一个好的例子,因为这会将整个数组["c", "d"]作为一个元素附加到数组letters中,所以letters将变成["a", "b", ["c", "d"]],请参见mongodb文档 - Amr Saber
5
$each操作符可与$addToSet配合使用,将数组中的所有元素添加到该数组中。使用{ $addToSet: { letters: { $each: [ "c", "d"] } } } 可以完成所需的工作。谢谢。 - SDK4551
完美符合我的需要! - Code Cooker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接