skip to Main Content

I wrote a simple updateMany statement to add a now field in a collection called products. As new products may not have an onSale property it may be added to the first time when those products now become eligible for onSale. However, older products which had already been onSale need to be update with onSale:false. Here is my update statement. I need to update the onSale: false when the sale ends for products.
I also notice that version 8.0.3 no longer accepts the {multi:true} anymore.

     public async updateProductsToOnSale(productIds: Array<string>, onSaleStatus: boolean): Promise<UpdateWriteOpResult | undefined> {
        try {
            return await Product.updateMany(
                {
                    _id: {
                        $in: productIds
                    }
                },
                { $set: { onSale: onSaleStatus } },            )
        } catch (error) {
            this.logger.error(error,`Update Failed for productIds  ${productIds}`);
        }
    }


The behavior I see that sometimes no rows are updated. However, when I print out the matched count I get matchedCount:1 even though the update did not work. Will this update work for setting a new onSale property as well as for an existing onSale property? If not is there a way to accomplish that with one updateMany or do I need 2 , one for the existing onSale and another to set a new onSale property? Thanks

2

Answers


  1. No,You don’t need two function, you can use bulkWrite

    let bulkUpdateOps = products.map(function(doc) { // you can warp this into your function
        return {
            "updateOne": {
                "filter": { "_id": doc.id },
                "update": { "$set": { onSale: true} },
                "upsert": true
            }
        };
    });
    
    Product.bulkWrite(bulkUpdateOps); // for mongoose model instance
    

    Mongoose bulk write doc

    Login or Signup to reply.
  2. Yes you can do this with one updateMany() function if you use an Aggregation Pipeline.

    Using $set without a query condition as the first parameter will add the onSale property to every document and by using a $cond you can specify which documents will be set to onSaleStatus via an $in operator.

    If an _id is $in your array of productIds then set it to onSaleStatus otherwise set it to false.

    An example would be:

    return await Product.updateMany({},
        [ 
            { 
                $set: { 
                    onSale: {
                        $cond: {
                            if: {
                                $in: [
                                    "$_id",
                                    productIds
                                ]
                            },
                            then: onSaleStatus,
                            else: false
                        } 
                    }
                } 
            },
        ]
    );
    

    See HERE for a full working example.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search