Incrementing number in an object of mongoose array

550 views Asked by At

I am trying to increment the number in MongoDB using mongoose. But I start failing right at the query stage. When I // @ts-ignore it flows silently with no error but the value doesn't update.

The error it throws out is: Type 'number' is not assignable to type 'undefined'

My Schema:

const CartSchema: Schema<Document<ICart>> = new Schema({
    clientID: { type: String, required: true },
    sourceID: { type: String, required: true },
    items: {
        id: { type: Types.ObjectId },
        amount: { type: Number },
        grindHow: { type: String, trim: true },
        grind: Boolean,
        package: { type: String, trim: true },
        price: { type: Number },
        productID: { type: String },
        productName: { type: String },
        totalProduct: { type: Number },
    },
    source: { type: String, required: true },
}, { collection: "carts", timestamps: true });

CartSchema.virtual('cartTotal').get(function() {
    // @ts-ignore
    const self: any = this;
    
    if(self.items && self.items.length) {
        return self.items.reduce((acc: BigNumber, current: any) => acc.plus(current.totalProduct), new BigNumber(0))
    } else {
        return 0
    }
})

The way I am trying to implement that is:

const item = await CartModel.findOneAndUpdate({ sourceID: clientID, 'items.id': itemID }, { $inc: { 'items.$.amount': 1 }}).lean({ virtuals: true })

I also tried with updateOne. I thought maybe it's more flexible.

That's where it highlights it

2

There are 2 answers

2
NeNaD On BEST ANSWER

items is not an array, it is an object. You should access it with items.amount and NOT with items.$.amount. Change your query like this:

const item = await CartModel.findOneAndUpdate({ sourceID: clientID, 'items.id': itemID }, { $inc: { 'items.amount': 1 }}).lean({ virtuals: true })
0
AudioBubble On

The issue was in two places there.

The issue with my Schema - I described it as an object (Thanks to @Nenad Milosavlievic) The correct Schema is (or close to correct. Any hints on Schema are welcomed):

const CartSchema: Schema<Document<ICart>> = new Schema({
    clientID: { type: String, required: true },
    sourceID: { type: String, required: true },
    items: { type: Array },
    source: { type: String, required: true },
}, { collection: "carts", timestamps: true });

and another issue with the way I'm querying for the item. I should have converted the string ID into ObjectId. I missed that out ...

It should have been like this (plus I need to return the updated value, so I am adding an option { new: true }):

await CartModel.findOneAndUpdate({ sourceID: clientID, 'items.id': Types.ObjectId(itemID) }, { $inc: { 'items.$.amount': 1 }}, { new: true }).lean({ virtuals: true })