【请教】Nodejs中mongoose 插入数据的时候,如何做冲突验证?
【请教】Nodejs中mongoose 插入数据的时候,如何做冲突验证?
schema如下:
new schema({ when{days: Number, start:Number, period:Number} where: String })
// days:15840 – 天数,是毫秒/86400000后的日期(也就可以确定当前日期,即2013-05-15) //start:9 – 时间,代表上午九点开始 //period:2 – 持续时间, 代表从九点开始,持续2小时,即11点结束。
以上就是schema的描述。
需求: 插入数据的时候,需要做when的冲突验证。时间上有冲突的话,不执行插入操作。
①我的想法是在.pre()方法里查询是否有和当前传入的when冲突的数据,
问题:不知道该如何来实现①中的查询。
对mongoose了解不多,请各位帮帮忙吧~~ 谢谢
当然可以!为了在插入数据时进行冲突验证(例如检查 when
字段是否与现有记录有时间重叠),你可以在 Mongoose 中使用 .pre('save')
钩子,并在其中查询数据库以检查是否存在冲突的时间段。以下是一个完整的示例代码,展示了如何实现这一点:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// 定义 schema
const mySchema = new Schema({
when: {
days: { type: Number, required: true },
start: { type: Number, required: true },
period: { type: Number, required: true }
},
where: { type: String, required: true }
});
// 在保存前进行冲突验证
mySchema.pre('save', async function (next) {
try {
const existingRecords = await this.model('MyModel').find({
$or: [
// 检查新的时间段是否与现有时间段重叠
{ 'when.days': this.when.days,
'when.start': { $lt: this.when.start + this.when.period },
'when.start': { $gt: this.when.start - this.when.period } },
{ 'when.days': this.when.days,
'when.start': { $lte: this.when.start },
'when.start': { $gte: this.when.start - this.when.period } }
]
});
if (existingRecords.length > 0) {
return next(new Error('Time conflict detected!'));
}
next();
} catch (error) {
next(error);
}
});
// 创建模型
const MyModel = mongoose.model('MyModel', mySchema);
// 示例插入操作
async function insertData() {
try {
const newData = new MyModel({
when: { days: 15840, start: 9, period: 2 },
where: 'somewhere'
});
await newData.save();
console.log('Data inserted successfully!');
} catch (error) {
console.error('Error inserting data:', error.message);
}
}
// 连接到 MongoDB
mongoose.connect('mongodb://localhost:27017/mydatabase', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Connected to MongoDB'))
.catch(err => console.error('Failed to connect to MongoDB', err));
// 执行插入操作
insertData();
解释
-
定义 Schema:
when
字段包含days
,start
, 和period
。where
字段为字符串。
-
.pre('save')
钩子:- 在保存文档之前,查询数据库以检查是否存在时间冲突。
- 使用
$or
查询条件来检查新的时间段是否与现有时间段重叠。
-
插入数据:
- 创建一个新的文档实例并尝试保存。
- 如果存在冲突,则抛出错误并阻止保存。
通过这种方式,你可以确保在插入新数据时不会出现时间上的冲突。希望这对你有所帮助!
某活动在2013-05-15,9点举行,持续2小时,到11点结束,换个说法就是某活动从2013-05-15 09:00开始,到2013-05-15 11:00结束。两者在信息上是等效的。业务对象的建模不一定非要100%照搬原始输入信息,在不丢失信息的前提下可以稍做变化嘛。
因此when{days: Number, start:Number, period:Number}
可以转变为when{startDate:Date, endDate:Date}
。如此,只要简单的检查是否存在when.startDate< date < when.endDate
这样的记录即可,最大限度的利用索引。
当然这样存取就多了一层转换,但是比起每次保存就检索全部数据并逐一对比,应该要好的多。至于既不转换时间格式也不扫描全体数据的办法,呃,楼下来吧。
要在Mongoose中实现插入数据时的冲突验证,可以利用Mongoose的中间件(middleware)和查询功能。具体来说,可以在插入数据之前使用pre('save')
中间件来检查是否有冲突的数据。
以下是实现步骤和示例代码:
步骤:
- 定义Schema:定义包含
when
字段的Schema。 - 创建Model:根据Schema创建Model。
- 使用
pre('save')
中间件:在保存前查询数据库,确保没有冲突的数据。
示例代码
const mongoose = require('mongoose');
// 定义Schema
const yourSchema = new mongoose.Schema({
when: {
days: { type: Number },
start: { type: Number },
period: { type: Number }
},
where: { type: String }
});
// 创建Model
const YourModel = mongoose.model('YourModel', yourSchema);
// 在保存前添加一个中间件来检查冲突
yourSchema.pre('save', async function (next) {
const existingData = await YourModel.findOne({
$or: [
{
'when.days': this.when.days,
'when.start': { $lt: this.when.start + this.when.period },
'when.start': { $gt: this.when.start - this.when.period }
},
{
'when.days': this.when.days,
'when.start': this.when.start,
'when.period': { $ne: this.when.period }
}
]
});
if (existingData) {
return next(new Error('Conflict detected!'));
}
next();
});
// 插入数据
async function insertData(data) {
try {
await new YourModel(data).save();
console.log('Data inserted successfully!');
} catch (error) {
console.error(error.message);
}
}
// 测试
insertData({
when: { days: 15840, start: 9, period: 2 },
where: 'Some Location'
});
解释:
yourSchema.pre('save', ...)
:在保存前运行的中间件。YourModel.findOne(...)
:查询数据库以查找是否有冲突的数据。- 冲突检测逻辑:查询
when.days
相同且start
时间在现有时间段内的记录。如果有冲突,则抛出错误。 next()
:调用next()
继续保存过程,如果冲突则抛出错误并停止保存。
通过这种方式,你可以确保在插入数据之前不会出现时间上的冲突。