如何利用Mongoose实现用户内项目名的唯一性约束?
你的方案行不通,给你几个正确实现思路
首先你写的这个方案跑不起来,问题出在两点:
- 你用了箭头函数写
set方法,箭头函数没有自己的this绑定,这里的this根本拿不到当前文档的username和project_name值 - 就算换成普通函数,
set方法里的this.project_name此时还没被赋值(set是处理传入的原始值),逻辑上也会绕不过来
要实现「同一用户的project_name不能重复,不同用户随便用」的需求,有两种靠谱的实现方式,推荐用第一种:
方案1:复合唯一索引(最推荐)
不需要拼接字段,直接给username和project_name加个复合唯一索引,MongoDB会自动帮你管控唯一性。
const mongoose = require('mongoose'); const ProjectSchema = new mongoose.Schema({ username: { type: String, required: true }, project_name: { type: String, required: true } }); // 核心:创建复合唯一索引,确保同一个用户的project_name唯一 ProjectSchema.index({ username: 1, project_name: 1 }, { unique: true }); const Project = mongoose.model('Project', ProjectSchema);
之后当你创建项目时,如果同一用户已经有同名项目,MongoDB会抛出重复键错误,你可以捕获这个错误给用户提示:
try { await Project.create({ username: 'userA', project_name: 'todo-list' }); } catch (err) { if (err.code === 11000) { console.log('你已经有这个项目啦'); } else { throw err; } }
方案2:拼接字段+唯一索引(如果一定要存拼接值)
要是你非得把username和项目名拼起来存成一个字段(比如叫unique_key),用它来保证唯一性,可以这么写:
方式A:用pre-save中间件
const ProjectSchema = new mongoose.Schema({ username: { type: String, required: true }, project_name: { type: String, required: true }, unique_key: { type: String, required: true, unique: true } }); // 保存前自动生成拼接值 ProjectSchema.pre('save', function(next) { // 这里必须用普通函数,this才指向当前文档实例 this.unique_key = `${this.username}-${this.project_name}`; next(); });
方式B:用set方法处理project_name
const ProjectSchema = new mongoose.Schema({ username: { type: String, required: true }, project_name: { type: String, required: true, unique: true, // 普通函数,this指向当前文档 set: function(inputProjectName) { return `${this.username}-${inputProjectName}`; } } });
不过这种方式要注意:创建文档时得先给username赋值,再设置project_name,不然this.username会是空的,不如复合索引灵活。
内容的提问来源于stack exchange,提问作者Ahmed M. Zanaty
相关产品推荐
相关产品推荐

