6

I'm working on a project where in one model I need to set the value of a field based on another fields value. Let me explain with some code.

Destination model

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const DestinationSchema = new Schema({
    name: {
        type: String, 
        required: true 
    },
    priority: {
        type: Number,
        default: 0,
        max: 10,
        required: true
    }
})

DestinationSchema.statics.getPriority = function(value) {
    return this.findOne({ _id: value })
}

const Destination = mongoose.model('Destination', DestinationSchema)

exports.Destination =  Destination

Task model

const mongoose = require('mongoose')
const { Destination } = require('../_models/destination.model')

const Schema = mongoose.Schema;

const TaskSchema = new Schema({
    priority: {
        type: Number,
        required: true,
        min: 0,
        max: 25
    },
    from: {
        type: Schema.Types.ObjectId,
        ref: 'Destination',
        required: true
    },
    to: {
        type: Schema.Types.ObjectId,
        ref: 'Destination',
        required: true
    },
    type: {
        type: Number,
        required: true,
        min: 0,
        max: 3
    }
}, { 
    timestamps: true
})

TaskSchema.pre('save', async function () {
    this.priority = await Destination.getPriority(this.from).then(doc => {
        return doc.priority
    })

    this.priority += await Destination.getPriority(this.to).then(doc => {
        return doc.priority
    })

    this.priority += this.type
})

Task Controller update function

exports.update = async function (req, res) {
    try {
        await Task.findOneAndUpdate({
                _id: req.task._id
            }, { $set: req.body }, {
                new: true,
                context: 'query'
            })
            .then(task =>
                sendSuccess(res, 201, 'Task updated.')({
                    task
                }),
                throwError(500, 'sequelize error')
            )
    } catch (e) {
        sendError(res)(e)
    }
}

When I create a new Task, the priority gets set in the pre save hook just fine as expected. But I'm hitting a wall when I need to change Task.from or Task.to to another destination, then I need to recalculate the tasks priority again. I could do it on the client side, but this would lead to a concern where one could just simply send a priority in an update query to the server.

My question here is, how can I calculate the priority of a Task when it gets updated with new values for from and to? Do I have to query for the document which is about to get updated to get a reference to it or is there another cleaner way to do it, since this would lead to one additional hit to the database, and I'm trying to avoid it as much as possible.

vice_versa
  • 99
  • 1
  • 9

1 Answers1

0

In your task schema.

you have to use pre("findOneAndUpdate") mongoose middleware. It allows you to modify the update query before it is executed

Try This code:

    TaskSchema.pre('findOneAndUpdate', async function(next) {
    if(this._update.from || this._update.to) {
        if(this._update.from) {
            this._update.priority = await Destination.getPriority(this._update.from).then(doc => {
                return doc.priority
            });
        }
        if(this._update.to) {
            this._update.priority += await Destination.getPriority(this._update.to).then(doc => {
                return doc.priority
            });
        }
    }
    next();
});
Mandeep
  • 364
  • 2
  • 16