【请教】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了解不多,请各位帮帮忙吧~~ 谢谢


3 回复

当然可以!为了在插入数据时进行冲突验证(例如检查 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();

解释

  1. 定义 Schema

    • when 字段包含 days, start, 和 period
    • where 字段为字符串。
  2. .pre('save') 钩子

    • 在保存文档之前,查询数据库以检查是否存在时间冲突。
    • 使用 $or 查询条件来检查新的时间段是否与现有时间段重叠。
  3. 插入数据

    • 创建一个新的文档实例并尝试保存。
    • 如果存在冲突,则抛出错误并阻止保存。

通过这种方式,你可以确保在插入新数据时不会出现时间上的冲突。希望这对你有所帮助!


某活动在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')中间件来检查是否有冲突的数据。

以下是实现步骤和示例代码:

步骤:

  1. 定义Schema:定义包含when字段的Schema。
  2. 创建Model:根据Schema创建Model。
  3. 使用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()继续保存过程,如果冲突则抛出错误并停止保存。

通过这种方式,你可以确保在插入数据之前不会出现时间上的冲突。

回到顶部