mongoDB/mongoose:如果不为null,则为唯一

ezm*_*use 91 mongoose mongodb node.js

我想知道是否有办法强制一个唯一的集合条目,但只有当条目不为空时.e示例模式:

var UsersSchema = new Schema({
    name  : {type: String, trim: true, index: true, required: true},
    email : {type: String, trim: true, index: true, unique: true}
});
Run Code Online (Sandbox Code Playgroud)

在这种情况下,'email'不是必需的,但如果保存'email',我想确保此条目是唯一的(在数据库级别).

空条目似乎得到值'null'所以每个条目都没有电子邮件与'unique'选项崩溃(如果有不同的用户没有电子邮件).

现在我正在应用程序级别上解决它,但是希望保存该数据库查询.

谢谢

Joh*_*yHK 148

从MongoDB v1.8 +开始,您可以通过sparse在定义索引时将选项设置为true 来获得确保唯一值的所需行为,但允许多个文档而不使用该字段.如:

email : {type: String, trim: true, index: true, unique: true, sparse: true}
Run Code Online (Sandbox Code Playgroud)

或者在shell中:

db.users.ensureIndex({email: 1}, {unique: true, sparse: true});
Run Code Online (Sandbox Code Playgroud)

需要注意的是独特的,稀疏索引仍然不允许多个文档与email同一个字段null,只有多个文档没有一个email领域.

http://docs.mongodb.org/manual/core/index-sparse/

  • 真棒!绝对是1.8之后像我这样的新手的最佳答案!注意:如果只是向模式添加稀疏:true,则Mongoose不会将您的唯一索引更新为稀疏.您必须删除并重新添加索引.Dunno,如果这是预期的或一个错误. (15认同)
  • "注意:如果db上已存在索引,则不会替换它." - http://mongoosejs.com/docs/2.7.x/docs/schematypes.html (7认同)
  • 不适用于缺少的字段.也许在mongodb的更高版本中行为发生了变化.答案应该更新. (2认同)

Mas*_*rAM 36

TL;博士

是的,可以做到.
将字段设置为null或未定义的多个文档,同时强制使用唯一的"实际"值.

要求:

  • MongoDB v3.2 +.
  • 当您的字段具有实际值时,它应该是特定类型(例如,始终是字符串).

怎么样?转到下面的实施细节.

更长的版本

为了补充@ Nolan的答案,从MongoDB v3.2开始,您可以使用带有过滤器表达式的部分唯一索引.

部分过滤器表达式具有局限性.它只能包括以下内容:

  • 等式表达式(即字段:值或使用string运算符),
  • object 表达,
  • null,implementation,$eq,$exists: true表情,
  • $gt 表达式,
  • $gte 仅限顶级运营商

这意味着$lt不能使用普通表达式.

但是,假设您的字段始终使用相同的类型,则可以使用$lte表达式.

{ field: { $type: <BSON type number> | <String alias> } }
Run Code Online (Sandbox Code Playgroud)

履行

猫鼬

您可以在mongoose模式中指定它:

{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
Run Code Online (Sandbox Code Playgroud)

或直接将其添加到集合(使用本机node.js驱动程序):

{email: {$type: ["string", "binData"]}}
Run Code Online (Sandbox Code Playgroud)

本地mongodb司机

运用 $type

const UsersSchema = new Schema({
  name: {type: String, trim: true, index: true, required: true},
  email: {
    type: String, trim: true, index: {
      unique: true,
      partialFilterExpression: {email: {$type: "string"}}
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

mongodb shell

使用$and:

User.collection.createIndex("email", {
  unique: true,
  partialFilterExpression: {
    "email": {
      $type: "string"
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

这将允许使用{"yourField"{$ne: null}}电子邮件插入多个记录,或者根本不插入电子邮件字段,但不允许使用相同的电子邮件字符串.

  • 这个问题的大多数公认答案都涉及确保您没有为索引键显式设置空值。而是将它们传递给 undefined。我这样做了,但仍然收到错误消息(在使用“unique”和“sparse”时)。我用这个答案更新了我的架构,删除了我现有的索引,它就像一个魅力。 (2认同)

小智 8

只是对研究此主题的人的快速更新。

所选答案将起作用,但您可能需要考虑使用部分索引。

在 3.2 版更改:从 MongoDB 3.2 开始,MongoDB 提供了创建部分索引的选项。部分索引提供了稀疏索引功能的超集。如果您使用的是 MongoDB 3.2 或更高版本,部分索引应优先于稀疏索引。

更多关于部分索引的文档:https ://docs.mongodb.com/manual/core/index-partial/