Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access a virtual attribute from within another virtual using Mongoose

I have an Invoice model that uses virtual attributes to compute values for tax, subtotal, total etc. The problem I have is that some of the virtual attributes need to be able to reference other virtual attributes.

For example, here is the Mongoose schema for the Invoice:

var InvoiceSchema = Schema({
    number: String,
    customer: {ref:String, email:String},
    invoiceDate: {type: Date, default: Date.now},
    dueDate: {type: Date, default: Date.now},
    memo: String,
    message: String,
    taxRate: {type:Number, default:0},
    discount: {
        value: {type:Number, default:0}, 
        percent: {type:Number, default:0}
    },
    items: [ItemSchema],
    payment: {type: Schema.Types.ObjectId, ref: 'Payment'}
});

InvoiceSchema.virtual('tax').get(function(){
    var tax = 0;

    for (var ndx=0; ndx<this.items.length; ndx++) {
        var item = this.items[ndx];
        tax += (item.taxed)? item.amount * this.taxRate : 0;
    }

    return tax;
});

InvoiceSchema.virtual('subtotal').get(function(){
    var amount = 0;

    for (var ndx=0; ndx<this.items.length; ndx++) {
        amount += this.items[ndx].amount;
    }

    return amount;
});

InvoiceSchema.virtual('total').get(function(){
    return this.amount + this.tax;
});

InvoiceSchema.set('toJSON', { getters: true, virtuals: true });

var ItemSchema = Schema({
   product: String,
   description: String,
   quantity: {type: Number, default: 1},
   rate: Number,
   taxed: {type: Boolean, default: false},
   category: String
});

ItemSchema.virtual('amount').get(function(){
    return this.rate * this.quantity;
});

ItemSchema.set('toJSON', { getters: true, virtuals: true });

module.exports = mongoose.model('Invoice', InvoiceSchema);

Now to understand the issue take a look at the virtual definition for 'tax' ...

InvoiceSchema.virtual('tax').get(function(){
    var tax = 0;

    for (var ndx=0; ndx<this.items.length; ndx++) {
        var item = this.items[ndx];
        tax += (item.taxed)? item.amount * this.taxRate : 0;
    }

    return tax;
});

... in this example item.amount, when called inside a virtual, doesn't use the virtual getter for item.amount.

Is there some way to tell Mongoose that I need to use the getter instead of trying to read a property that doesn't exist?

like image 276
ra9r Avatar asked Sep 18 '25 18:09

ra9r


1 Answers

Did you try item.get('amount')? That seems to be the explicit way of using virtuals.

Got it from this Issue: https://github.com/Automattic/mongoose/issues/2326 Didn't find anything else related unfortunately.

like image 154
Jonas Krispin Avatar answered Sep 21 '25 12:09

Jonas Krispin