Search code examples
node.jsmongodbvalidationmongoosemongoose-schema

Mongoose Validations/Hooks based on most recent record in table (if exists) | Model for a Bank Account


I am designing a bank account schema, which looks like follows:

const bankAccountSchema = new mongoose.Schema({
    transactionType: {
        type: String,
        enum: ['credit', 'debit']
        required: true
    },
    amount: {
        type: Number,
        required: true
    },
    balance: {
        type: Number,
        min: 0,
        required: true
    }
}, {
    timestamps: true
})

const BankAccount = mongoose.model('BankAccount', bankAccountSchema)

As far as the user is concerned, they can only add or remove amount (positive or negative) from the account. The balance column is supposed to keep track of the running total in the account. In the route, I already have code that prevents the user from withdrawing more money than he has in the account but I am wondering if it is possible to set up the following validations/hooks for my model as well:

  1. Before saving, automatically update the balance and transactionType (credit if amount is positive, debit if amount is negative) columns based on amount and previous record's balance (if exists) so that records can be created simply by the command new BankAccount({ amount: 100 }).save() without explicitly stating appropriate balance or transactionType.
  2. Should be unable to withdraw more than is available in account i.e. if the previous record's balance is 100 then amount for a new record can never be less than -100.

Both (1) and (2) require accessing the previous record in the table (if exists) before save. Can this be done or do I have to depend solely on my route for validation?


Solution

  • I solved this using an async validator and the this.constructor keyword like follows:

    const bankAccountSchema = new mongoose.Schema({
        transactionType: {
            type: String,
            enum: ['credit', 'debit']
            required: true
        },
        amount: {
            type: Number,
            required: true
        },
        balance: {
            type: Number,
            min: 0,
            required: true,
            async validate(balance) {
                // Make DB calls here
                console.log(await this.constructor.countDocuments())
            }
        }
    }, {
        timestamps: true
    })
    
    const BankAccount = mongoose.model('BankAccount', bankAccountSchema)