admin管理员组

文章数量:1327803

I'm creating a CronJob that calls an API and store its response in the database:

const CronJob = require("cron").CronJob;
const btc_price_ticker = require("../../controllers/BtcExchange/Ticker");
const currency = require("../../controllers/Currencies/CurrenciesController");

module.exports = new CronJob("* * * * * *", async function() {
  const {
    ticker: { sell }
  } = await btc_price_ticker.getBtcPrice();
  currency
    .update({
      params: {
        id: "5cbdf078f5bcec257fcec792"
      },
      body: {
        exchange_rate: sell,
        lastUpdate: Date.now()
      }
    })
    .catch(error => console.log(error));
});

It works fine, however I receive a TypeError: Cannot read property 'json' of undefined

I'm using the same function to update the database I use when updating by my API:

module.exports = {
  async update(req, res) {
    const currency = await Currency.findByIdAndUpdate(req.params.id, req.body, {
      new: true
    });
    return res.json(currency);
  }
};

The TypeError happens in the return res.json(currency), and it only happens when it's called by the CronJob. When I put new information by API, it doesn't show any error.

I think it happens because when I call the function in CronJob, I just pass the req by parameter, but I don't know how to solve it. What am I supposed to do?

Thanks in advance!

I'm creating a CronJob that calls an API and store its response in the database:

const CronJob = require("cron").CronJob;
const btc_price_ticker = require("../../controllers/BtcExchange/Ticker");
const currency = require("../../controllers/Currencies/CurrenciesController");

module.exports = new CronJob("* * * * * *", async function() {
  const {
    ticker: { sell }
  } = await btc_price_ticker.getBtcPrice();
  currency
    .update({
      params: {
        id: "5cbdf078f5bcec257fcec792"
      },
      body: {
        exchange_rate: sell,
        lastUpdate: Date.now()
      }
    })
    .catch(error => console.log(error));
});

It works fine, however I receive a TypeError: Cannot read property 'json' of undefined

I'm using the same function to update the database I use when updating by my API:

module.exports = {
  async update(req, res) {
    const currency = await Currency.findByIdAndUpdate(req.params.id, req.body, {
      new: true
    });
    return res.json(currency);
  }
};

The TypeError happens in the return res.json(currency), and it only happens when it's called by the CronJob. When I put new information by API, it doesn't show any error.

I think it happens because when I call the function in CronJob, I just pass the req by parameter, but I don't know how to solve it. What am I supposed to do?

Thanks in advance!

Share Improve this question asked Apr 22, 2019 at 17:48 Otavio BonderOtavio Bonder 1,9995 gold badges22 silver badges38 bronze badges 7
  • do you have express using bodyparser – Len Joseph Commented Apr 22, 2019 at 17:49
  • You're calling update() without passing the response object as the second argument – Nir Alfasi Commented Apr 22, 2019 at 17:51
  • Yes @alfasin, you are right. I'm pretty sure this is the error, but I don't know what should I pass as the response object – Otavio Bonder Commented Apr 22, 2019 at 17:52
  • @OtavioBonder Ideally you should simply call Currency.findByIdAndUpdate or any other mon util function in the Corn rather than mocking req and res – priyansh gupta Commented Apr 22, 2019 at 18:04
  • If you're using cron-job, why do you need req/res from the first place? – Nir Alfasi Commented Apr 22, 2019 at 18:21
 |  Show 2 more ments

3 Answers 3

Reset to default 3

There's a famous saying which says that you can solve almost any problem in CS by adding another layer of indirection. This is one of those cases:

Instead of of declaring your module as:

module.exports = {
  async update(req, res) {
    const currency = await Currency.findByIdAndUpdate(req.params.id, req.body, {
      new: true
    });
    return res.json(currency);
  }
};

Separate the logic from the route-logic:

module.exports = {

  async getCurrency(id, params) {
      const currency = await Currency.findByIdAndUpdate(id, params, {
        new: true
      });
      return currency;
  }

  async update(req, res) {
    const currency = await getCurrency(req.params.id, req.body);
    return res.json(currency);
  }
};

Now the route can call update() and the cron-job can call getCurrency() directly.

Ok, maybe my approach isn't the best, but since I'm passing an undefined object to update(), and I don't need the response, I edited the update function:

async update(req, res) {
    const currency = await Currency.findByIdAndUpdate(req.params.id, req.body, {
      new: true
    });
    if (res !== undefined) {
      return res.json(currency);
    }
  }

So, since res is undefined, it doesn't return anything.

It's because both req and res is undefined (or atleast not the proper request and response object) when the route is not requested by client (which is the case here).

Simplest solution I can think of is mock (or make an actual call) a client call in your cron job by using modules like axios, request, request-promise (with Promise wrapper on top of request) like:

const rp = require('request-promise')

module.exports = new CronJob("* * * * * *", async function() {
  try {
    const {
      ticker: { sell }
    } = await btc_price_ticker.getBtcPrice();
    // assuming your server is running in localhost, port 3000 and route is 'myapi/:id'
    const url = "http://localhost:3000/myapi/5cbdf078f5bcec257fcec792";
    const options = {
      method: 'GET',
      uri : url,
      json: true,
      body: {
        exchange_rate: sell,
        lastUpdate: Date.now()
      }
    }
    const response = await rp(url);
  } catch(error) {
    console.log(error);
  }
});

Since you can execute the db methods, a simpler alternative would be to directly execute Currency.findByIdAndUpdate in your cron job. I don't see any reason why you would want to call your route in your code.

本文标签: javascriptNodeJS TypeError Cannot read property 39json39 of undefinedStack Overflow