问题 Mongoose模式:验证唯一字段,不区分大小写


我有一个 userSchema 像这样:

var userSchema = new Schema({
    name: {
      type: String
    , required: true
    , validate: [validators.notEmpty, 'Name is empty']
    }
  , username: {
      type: String
    , required: true
    , unique: true
    , validate: [validators.notEmpty, 'Username is empty']
    }
});

username 字段应该是唯一的。如果此用户名已存在于数据库中,则Mongoose将抛出错误。但是,它不是不区分大小写的,我需要它。

我是否正确地认为实现不区分大小写的唯一检查的唯一方法是编写我自己的验证规则,该规则将对集合执行查询?可以编写这样的验证检查,创建更多与集合的连接吗?我需要做类似的事情 email也是。


8252
2017-12-21 14:05


起源



答案:


怎么样使用:

{ type: String, lowercase: true, trim: true }

实现你的目的?


14
2017-12-21 14:13



那不会强制用户名小写吗?我希望用户名检查不区分大小写,而不强制用户名具有小写用户名。
这个技巧将使您免于对数据库的其他查询。但是为了将用户名保留在原始大小写中,您可以拥有一个单独的字段,而不是用于唯一性。 - sqreept
好建议,但似乎有点hacky。进行更多额外查询是否昂贵?请记住,我需要对其他领域进行类似的检查。
这是迄今为止我能找到的最佳解决方案: fabianosoriani.wordpress.com/2012/03/22/...。
其他查询更昂贵,并且情况的严重性在很大程度上取决于您的数据库大小,结构和网络布局。如果app服务器与MongoDB在同一台机器上,则其他查询并不昂贵。如果它们很远,你就可以为每个查询喝一口咖啡。 - sqreept


答案:


怎么样使用:

{ type: String, lowercase: true, trim: true }

实现你的目的?


14
2017-12-21 14:13



那不会强制用户名小写吗?我希望用户名检查不区分大小写,而不强制用户名具有小写用户名。
这个技巧将使您免于对数据库的其他查询。但是为了将用户名保留在原始大小写中,您可以拥有一个单独的字段,而不是用于唯一性。 - sqreept
好建议,但似乎有点hacky。进行更多额外查询是否昂贵?请记住,我需要对其他领域进行类似的检查。
这是迄今为止我能找到的最佳解决方案: fabianosoriani.wordpress.com/2012/03/22/...。
其他查询更昂贵,并且情况的严重性在很大程度上取决于您的数据库大小,结构和网络布局。如果app服务器与MongoDB在同一台机器上,则其他查询并不昂贵。如果它们很远,你就可以为每个查询喝一口咖啡。 - sqreept


我不知道你是否在节点中这样做。但你可以像这样使用npm: https://github.com/blakehaswell/mongoose-unique-validator 检查集合字段的唯一验证。其他方式可能是每次新请求到来时检查集合。 http://timstermatic.github.io/blog/2013/08/06/async-unique-validation-with-expressjs-and-mongoose/ 您可以在此处参考材料,并以适合您的情况的方式使用它。


2
2018-03-03 19:08



虽然您提供的链接可能会回答这个问题,但最好将解决方案的基本部分直接放在Stack Overflow应答中,以防链接在将来过期。 - Kmeixner
都 mongoose-unique-validator 并且timstermatic博客中的技术存在根本缺陷,因为它们在插入/更新之前执行单独的查询以检查唯一性,因此如果在验证器运行之后运行另一个插入/更新,则两者都将插入。看到 github.com/blakehaswell/mongoose-unique-validator#caveats。保证唯一性的唯一方法是使用数据库中的唯一索引。 - ZachB


最好的方法是使用已存在的npm包,如下所示。      https://www.npmjs.com/package/mongoose-unique-validator

为了使其区分大小写,您可以关注 uniqueCaseInsensitive 在同一页面。

当已经有可用的包时,无需编写自己的验证逻辑(如下) 阿维纳什的帖子 太)。


1
2017-10-28 10:51





很简单的解决方案

username : {
        trim:true,
        //lowercase:true,

        type:String,
        required:[true, '{PATH} is required.'],
        match : [
            new RegExp('^[a-z0-9_.-]+$', 'i'),
            '{PATH} \'{VALUE}\' is not valid. Use only letters, numbers, underscore or dot.'
        ],
        minlength:5,
        maxlength:30,
        //unique:true

        validate : [
            function(un, cb){
                console.log(v);
                student.findOne({username:/^un$/i}, function(err, doc){
                    if(err) return console.log(err);
                    if(!_.isEmpty(doc)) return cb(false);
                    return cb(true);
                });
            },
            'Username already exists.'
        ]
    },

在这里,我使用异步验证并检查我的模型 student 如果存在相同的字段。如果你愿意,使用显然可以使用正则表达式。

但我不推荐这种方法,它只是不适合我的想法。

相反坚持 { type: String, lowercase: true, trim: true, unique:true } 接近并将原始用户名复制到其他字段,以备不时之需。


0
2017-07-10 11:15





使用正则表达式怎么样?

var pattern = [ /some pattern/, "{VALUE} is not a valid user name!" ];

{ type: String, match: pattern }

供进一步参考: http://mongoosejs.com/docs/api.html#schematype_SchemaType-required


-1
2018-02-10 09:08