Mongoose,将默认值设为null并设置唯一性

12

我正在尝试创建一个用户架构,其中包含一个名为“facebookid”的键,这是一个唯一的值,仅在用户使用Facebook注册时才会给出,而当用户通过Google或本地注册时则不会。当用户本地注册时,“facebookid”将被设置为默认值null。然而,我遇到了错误:'insertDocument :: caused by :: 11000 E11000 duplicate key error index: db22.users.$facebookid_1 dup key: { : null }'

此处是架构:

let UserSchema = new Schema({
    facebookid: {
        type: String,
        required: false, // only required for facebook users
        unique: true,
        default: null
    },
    // more details + keys below ...
})

如果facebookid的值为空,我如何允许键的重复输入,但同时又要确保条目是唯一的呢?

也就是说,我不想看到两个相似的字符串条目:
不可以的情况:

* User: {_id: 123, facebookid: '4325',username:'joe'}
* User: {_id: 432, facebookid: '4325', username: 'pat'}
* User: {_id: 123, facebookid: null,username:'joe'}
* User: {_id: 432, facebookid: null, username: 'pat'}

你需要将唯一性设置为false。 - Sombrero
3个回答

14

您可以使用partialFilterExpressions

facebookid: {
  type: String,
  required: false, // only required for facebook users
  index: {
    unique: true,
    partialFilterExpression: { facebookid: { $type: 'string' } },
  },
  default: null,
 }

这允许null被多次使用。

更改唯一性约束后,请记得重新启动 Mongoose 和所有相关内容。如果您还没有看过,请查看此问题


感谢@MikaS。顺便说一下,重启Mongo并没有帮助,我删除了数据库,然后它就开始工作了,你知道为什么吗? - Boris Savic
那么使用 partialFilterExpression 和使用 sparse: false 的方法有什么区别呢? - Normal

4

感谢 @Mikas

额外的奖励 - 您可以使用以下方式引用嵌套键:"key1.key2"。
不幸的是,$ne目前不受支持,因此您不能简单地使用:$ne: null。

    key1: {
        key2: {
            type: String,
            index: {
                unique: true,
                partialFilterExpression: {
                    "key1.key2": {
                        // $ne: null,
                        $type: Schema.Types.String
                    }
                },

            },
            default: null
        }

2

针对这种情况,您不应在模式中使用 unique: true,而是必须检查 facebookid 是否已经存在,因此您可以使用 schemaName.path 添加验证,并检查唯一性。例如下面的代码。

let UserSchema = new Schema({
    facebookid: {
        type: String,
        required: false,
        default: null
    },
    // more details + keys below ...
})

UserSchema.path('facebookid').validate(function(value, next){
  if(!value) {
    return next();
  }
  // I assueme your model name is User
  mongoose.models['User'].findOne({facebookid: value }, function(err, found){
    if(err){
      return next(false);
    }

    if(found && found.facebookid){
      return next(false, "Already exist this facebook ID");
    }else{
      return next();
    }
  });

});

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