Mongo db with Monk: error catching and handling if

2020-04-11 13:13发布

I'm new to Mongo. I needed a database for a simple project and ended up following a tutorial using Mongo with Monk but I have problems understanding how to handle errors.

Background: I have a registration form on the client side. When the user clicks a button, the data is sent via AJAX to the controller that (upon validation, but this is not relevant now) inserts such data into the database and sends back either success or error. When the db is up all seems to work fine.

The problem: If I don't start the db and try to send the request anyway, no error is returned. Simply nothing happens. After some time on the console I get: POST /members/addmember - - ms - -.

I think some error should be returned to the user in this case, so how could I do this?

The post request is below (pretty much as from the tutorial):

// app.js 

var db = monk('localhost:27017/dbname')
[...]
// I realize it might be not optimal here
app.use(function(req,res,next){ 
    req.db = db;
    next();
});

// members.js

router.post('/addmember', function(req, res) {
  var db = req.db;
  var collection = db.get('memberstest');
  collection.insert(req.body, function(err, result){
    res.json(
      (err === null) ? { msg: 'success' } : { msg: err }
    );
  });
});

If the db is down I guess the problem is actually even earlier than the insert, that is in that "db.get()". So how to check if that get can actually be done? I suppose that given the asynchronous nature of node something like a try/catch would be pointless here. Correct?

EDIT: After Neil's answer and a bit of trying, I put together the following that seems to do the job. However, given my scarce degree of confidence on this, I'd appreciate a comment if the code below works because it makes sense or by chance. I added the bufferMaxEntries: 0 options and modified the controller as follows. In the ajax callback I simply have an alert for now that shows the error message thrown (if any).

router.post('/addmember', async (req,res) => {

    try {
      let db = req.db;
      let collection = db.get('memberstest');

      collection.insert(req.body, function(err, result){
      res.json(
        (err === null) ? { msg: 'success' } : { msg: err }
      );
    });

    await db.then(() => 1);

    } catch(e) {
      res.json({msg: e.message})
    }

});

1条回答
男人必须洒脱
2楼-- · 2020-04-11 13:36

Well you can actually set the bufferMaxEntries option ( documented under Db but deprecated for that object usage, use at "top level as demonstrated instead" ) on the connection, which essentially stops "queuing" requests on the driver when no connection is actually present.

As a minimal example:

index.js

const express = require('express'),
      morgan = require('morgan'),
      db = require('monk')('localhost/test',{ bufferMaxEntries: 0 }),
      app = express();

const routes = require('./routes');

app.use(morgan('combined'));

app.use((req,res,next) => {
  req.db = db;
  next();
});

app.use('/', routes);

(async function() {

  try {

    await db.then(() => 1);

    let collection = db.get('test');
    await collection.remove({});

    await collection.insert(Array(5).fill(1).map((e,i) => ({ a: i+1 })));
    console.log('inserted test data');

    await app.listen(3000,'0.0.0.0');
    console.log('App waiting');

  } catch(e) {
    console.error(e);
  }

})();

routes.js

var router = require('express').Router();

router.get('/', async (req,res) => {
  try {
    let db = req.db,
        collection = db.get('test');

    let response = await collection.find();
    res.json(response);
  } catch(e) {
    res.status(500).json(e);
  }
});

module.exports = router;

So I am actually awaiting the database connection to at least be present on "start up" here, but really only for example since I want to insert some data to actually retrieve. It's not required, but the basic concept is to wait for the Promise to resolve:

await db.then(() => 1);

Kind of trivial, and not really required for your actual code. But I still think it's good practice.

The real test is done by stopping mongod or otherwise making the server unreachable and then issuing a request.

Since we set the connection options to { bufferMaxEntries: 0 } this means that immediately as you attempt to issue a command to the database, the failure will be returned if there is no actual connection present.

Of course when the database becomes available again, you won't get the error and the instructions will happen normally.

Without the option the default is to "en-queue" the operations until a connection is resolved and then the "buffer" is essentially "played".

You can simulate this ( as I did ) by "stopping" the mongod daemon and issuing requests. Then "starting" the daemon and issuing requests. It should simply return the caught error response.

NOTE: Not required, but in fact the whole purpose of async/await syntax is to make things like try..catch valid again, since you can actually scope as blocks rather than using Promise.catch() or err callback arguments to trap the errors. Same principles apply when either of those structures are actually in use though.

查看更多
登录 后发表回答