如何限制Mongoose Schema中属性仅接受数据库已存在的设备名?
解决方案:自定义Mongoose验证器校验兼容性设备列表
要实现incompatibleWithDevices数组仅接受数据库中已存在的设备名称,最适合的方案就是使用Mongoose自定义异步验证器,以下是具体实现步骤:
1. 编写异步验证函数
这个函数会遍历待验证的设备名称列表,查询数据库确认每个名称是否存在,同时处理去重和排除当前设备的逻辑:
async function validateIncompatibleDevices(devices) { // 空数组直接通过验证 if (!devices || devices.length === 0) return true; // 去重,避免重复查询同一设备,提升效率 const uniqueDeviceNames = [...new Set(devices)]; // 查询数据库中匹配的设备数量 const existingDeviceCount = await DeviceModel.countDocuments({ deviceName: { $in: uniqueDeviceNames }, // 排除当前设备自身(更新场景下避免把自己加入不兼容列表) _id: { $ne: this._id } }); // 若匹配数量与去重后的列表长度一致,说明所有设备都存在 return existingDeviceCount === uniqueDeviceNames.length; }
2. 将验证器绑定到Schema字段
把上面的验证函数添加到incompatibleWithDevices字段的配置中,同时自定义错误提示信息:
const schema = new Schema({ deviceName: { type: String, required: true, unique: true}, category: { type: String, enum: DEVICE_CATEGORIES, required: true }, incompatibleWithDevices: { type: [String], validate: { validator: validateIncompatibleDevices, // 自定义错误消息,提示具体无效值 message: (props) => `设备名称列表中包含不存在的项:${props.value}` } } }); const DeviceModel = model("Device", schema);
关键注意事项
- 异步验证支持:Mongoose原生支持异步验证器,这里使用
async/await处理数据库查询,确保验证逻辑正确等待异步操作完成。 - 去重优化:对输入数组去重后再查询,减少数据库请求次数,提升性能。
- 排除自身逻辑:通过
this._id排除当前设备,避免在更新时将自身加入不兼容列表(创建新设备时this._id为null,$ne: null会自动忽略该条件,不影响新设备的验证)。 - 错误提示:自定义错误消息可以明确告知用户哪些设备名称无效,便于调试和用户反馈。
测试示例
// 先创建一个合法设备 await DeviceModel.create({ deviceName: "Phone", category: "Mobile" }); // 创建包含合法设备的记录,验证通过 await DeviceModel.create({ deviceName: "Tablet", category: "Mobile", incompatibleWithDevices: ["Phone"] }); // 创建包含不存在设备的记录,会抛出验证错误 try { await DeviceModel.create({ deviceName: "Laptop", category: "Computer", incompatibleWithDevices: ["TV"] }); } catch (err) { console.log(err.message); // 输出:设备名称列表中包含不存在的项:TV }
内容的提问来源于stack exchange,提问作者ethdude12
相关产品推荐
相关产品推荐

