1

I'm trying to update multiple document with mongoose using node-cron. What I'm trying to accomplish is all documents that was created, let's say, July 1, will have an status of inactive after 30 days.

I manage to update multiple document using the code below but I don't know how to update multiple documents with products which date is less than the current date:

I know how to get the list of product that is less than the current date using but I don't know how to apply this logic to the code below -

let currentDate = new Date();
let query = Product.find({ dateCreated: {$lt: currentDate}});

Code is unrelated to what I'm trying to accomplish. This is a sample code that will update multiple documents every 10 seconds.

const mongoose  = require('mongoose');
const Product   = require('../model/product');
const cron      = require('node-cron');

cron.schedule('*/10 * * * * *', function(){
    let productArray = ['Bacon', 'Apple', 'Fork', 'Beans'];
    productArray.map(product => updateProduct(product));
});

let updateProduct = (name) => {
    let randomNumber = Math.floor(Math.random() * (999 - 1 + 1));
    let query = Product.findOne({name: name}).select({ 'name': 1 });
    query.exec((err, product) => {
        if(err) throw err;
        if(product){
            product.description = `Random description generate every 10 seconds: ${randomNumber}`;
            product.save(err =>{
                if(err) throw err;
                console.log(`Successfully updated random description for: ${product.name}\n ${product.description}\n`); 
            });
        }
    });
};

Product Schema

const mongoose = require('mongoose');
const Schema   = mongoose.Schema;

const productSchema = mongoose.Schema({
    name            :   String,
    description     :   String,
    status          :   String,
    dateCreated     :   { type: Date, default: Date.now }, // 
});

module.exports = mongoose.model( 'Product', productSchema );

This is the only way I know to update multiple document in mongoose. So is there other way to update multiple document in mongoose after 30 days of creation using mongoose and node-cron? Pardon me if my question is confusing.

  • Have you tried query like this `Product.update({name : { $in : productArray }, dateCreated: {$lt: currentDate} }, {status : 'inactive' },{multi: true}, callbackfn())` – Prabodh M Jul 05 '17 at 04:42
  • Ohh not yet. That's a good idea but what if the productArray is dynamic? Will querying the list of products then use the query you mentioned create a heavy load to may app? Let's say::: get the list of product (Main query) then after finding the list of product - set the result of the main query to productArray then execute subQuery(your query)? – Sherwin Ablaña Dapito Jul 05 '17 at 04:49
  • 1
    Are you trying to say, querying for each array element is better than querying all at once. You are mistaken there my friend. Cause If you let the mongoose handle the multi update on its own, it will be faster than what you have tried to achieve. Also you have made calls in loop to async method of update. So your code will be slow as well and not optimised. – Prabodh M Jul 05 '17 at 04:54
  • You are welcome, I've added a solution. It will be a single call to DB with flexibility to log the transaction status at one point. Hope it servers your purpose! – Prabodh M Jul 05 '17 at 05:05

1 Answers1

3

Here you go the full version of code.

Here you no need to make multiple queries, like first selecting all the products whose currentdate has matched your criteria. Cause that you can do while updating the products itself.

const mongoose = require('mongoose');
const Product = require('../model/product');
const cron = require('node-cron');

cron.schedule('*/10 * * * * *', function() {
    let productArray = ['Bacon', 'Apple', 'Fork', 'Beans'];
    updateAllProducts(productArray, (err, res) => {
        if (err)
            //error handle, you can log here
        else
        //success handle, you can log here
    })
});

let updateAllProducts = (productArray, callbackFn) => {
    let randomNumber = Math.floor(Math.random() * (999 - 1 + 1));
    description = `Random description generate every 10 seconds: ${randomNumber}`;
    Product.update({
        name: {
            $in: productArray
        },
        dateCreated: {
            $lt: currentDate
        }
    }, {
        description: description
    }, {
        multi: true
    }, (err, res) => {
        if (err) {
            callbackFn(err, null)
        } else {
            callbackFn(null, err);
        }

    });

};

In this case you can also log if Db update was failure or success. So there is better control over code. Rather than making multiple Calls in loop. That would be really time consuming and error prone.

Hope this helps!

Prabodh M
  • 2,132
  • 2
  • 17
  • 23
  • Ohh the multi: true to update multiple documents right??. Thank you so much for your response mate. This will surely helps a lot. I will marked it answer. Kudos to you. – Sherwin Ablaña Dapito Jul 05 '17 at 05:17
  • Yeah you got it right mate. If you want to update all matched element, you need to set the multi attribute to true. – Prabodh M Jul 05 '17 at 05:18