mongodb 在mongoose中使用create命令运行排序规则

biswetbf  于 2022-11-03  发布在  Go
关注(0)|答案(4)|浏览(202)

我试图使我的用户模型不关心emailusername字段的大小写敏感性。因此,如果我试图创建一个用户的电子邮件为Thisemail@email.com,另一个用户的电子邮件为thisemail@email.com,第二次是不允许的,因为电子邮件不是唯一的,尽管有大小写。
我的使用者结构描述如下:

const UserSchema = new mongoose.Schema({
  email: {
    type: String,
    unique: true,
    required: true,
    validate: // validators here,
  },
  username: {
    type: String,
    unique: true,
    required: true,
    validate: // validators here,
  },
  // Some other fields not case insensitive
});

使用mongoose创建函数创建用户:

user = await User.create(userData)

我尝试过创建一个排序规则,它可以直接在mongo shell上使用find命令。

db.users.createIndex({'email': 1}, {'collation': { 'locale': 'en', 'strength': 2}, 'name': 'testcollation'})
db.users.find({'email':'thisemail@email.com'}).collation({'locale':'en', 'strength': 2})

但是当我试图将排序规则附加到create调用时,我得到一条错误消息,说排序规则函数不存在。

user = await User.create(userData).collation({ "locale": "en", "strength": 2 });

在这个链接https://mongoosejs.com/docs/api.html#query_Query-collation之后,我希望这个链接可以运作:

User.create(...).collation is not a function

知道如何用create函数运行排序规则吗?

5t7ly7z5

5t7ly7z51#

如果使用该排序规则在email上创建unique index,则应禁止在数据库级别创建重复的电子邮件:
db.users.createIndex({'email': 1}, { 'collation': { 'locale': 'en', 'strength': 2 }, unique: true, 'name': 'testcollation' })
创建此索引会使您的重复User.create调用失败。Mongoose架构unique选项会自动创建一个类似的索引,但它不会知道您所需的排序规则。我不确定是否有一种方法可以设置Mongoose架构设置以使其创建您所需的索引。
您也可以在createCollection调用中设置集合级别的排序规则。但是,您不能修改现有集合以使用不同的排序规则:这将仅对初始集合创建起作用。

yuvru6vn

yuvru6vn2#

不能将归类与create一起使用,因为它只能与find游标一起使用
指定由db.collection.find()返回的游标的排序规则。若要使用,请追加到db.collection.find()
对于您的方案,您可能需要使用预保存挂接
例如:

schema.pre("save", function(next) {
  // ...do something with "this"
  next();
});
gmxoilav

gmxoilav3#

要在mongoose中使用create命令运行collation,需要在架构定义或create方法中指定collation选项。Collation是一种功能,它允许您指定比较不同语言和字母的字符串的规则。例如,您可以使用collation使用户模型在电子邮件和用户名字段中不区分大小写。

说明

Mongoose是MongoDB(一种NoSQL数据库)的常用对象数据建模(ODM)库。Mongoose允许您为集合定义模式,这些模式就像文档的蓝图。模式可以有各种选项,如验证器、索引、挂钩、虚拟和排序规则。
排序规则是一个选项,可让您定义排序和比对字串的语言特定规则。例如,您可以使用排序规则,让您的使用者模型忽略电子邮件和使用者名称字段的大小写,以便将Thisemail@email.com和thisemail@email.com视为相同。您也可以使用排序规则,根据不同的字母(例如阿拉伯文、斯拉夫文或拉丁文)来排序字串。
要在mongoose中使用collation,你需要在模式定义或create方法中指定collation选项。collation选项是一个对象,它有几个属性,如locale、strength、caseLevel和caseFirst。你可以在MongoDB文档中找到collation属性及其含义的完整列表:https://docs.mongodb.com/manual/reference/collation/
例如,若要使您的使用者模型在电子邮件和使用者名称字段中不区分大小写,您可以使用下列定序选项:

collation = {
  'locale': 'en', # use English as the language
  'strength': 2, # ignore case and diacritics, such as accents
  'caseLevel': False, # do not distinguish between base characters and case variants
  'caseFirst': 'off' # do not sort uppercase before lowercase or vice versa
}

然后,您可以将此排序规则选项应用于用户方案或创建方法。例如:


# define the user schema with the collation option

userSchema = mongoose.Schema({
  email: {type: String, required: True, unique: True},
  username: {type: String, required: True, unique: True},
  password: {type: String, required: True}
}, {collation: collation})

# create the user model from the schema

User = mongoose.model('User', userSchema)

# create a new user with the collation option

User.create({
  email: 'Thisemail@email.com',
  username: 'Thisuser',
  password: '123456'
}, {collation: collation}, (err, user) => {
  if (err) {
    console.error(err)
  } else {
    console.log(user)
  }
})

示例
以下是mongoose中排序规则工作方式的一些示例:

  • 如果您使用电子邮件Thisemail@email.com和用户名Thisuser创建一个用户,然后尝试使用电子邮件thisemail@email.com和用户名thisuser创建另一个用户,则会出现重复键错误,因为排序规则选项使它们等效。
  • 如果您使用电子邮件Thisemail@email.com与用户名Thisuser创建用户,然后尝试通过电子邮件thisemail@email.com或用户名thisuser查找他们,则您将获得相同得用户,因为排序规则选项使他们匹配.
  • 如果您使用电子邮件Thisemail@email.com和用户名Thisuser创建一个用户,然后尝试按电子邮件或用户名对它们进行排序,则无论大小写如何,您都将得到相同的顺序,因为排序规则选项使它们相等。
xzabzqsa

xzabzqsa4#

个人而言,我更喜欢先查询,如果有重复,创建或出错。在你的情况下,我会使用一个简单的正则表达式来检查大小写不敏感性。

const checkUserDuplicate = await User.find({ email: { $regex: `${userData.email}`, $options: 'i' }});
if (checkUserDuplicate && checkUserDuplicate.email === userData.email) {
  return next(res.status(500).json('Email already in use'));
} else {
  const user = await User.create(userData);
  res.status(201).json(user);
}

根据docs这类中间件保存后应该运行。

UserSchema.post('save', function (error, doc, next) {
  if (error.name === 'MongoServerError' && error.code === 11000) {
    next(console.log('Email address already in use'))
  }
  else {
    next()
  }
})

然后,您可以将lowercase: true加入user.email结构描述属性,此属性永远会在值上呼叫.toLowerCase()

相关问题