2

I'm using Node.js, Hapi and MongoDB Native Driver (node-mongodb-native)

I want to access the db object returned by the get() method from db.js in my handler in server.js.

db.js

'use strict'

const MongoClient = require('mongodb').MongoClient

let _db

function connect (url) {
  return MongoClient.connect(url, { server: { poolSize: 5 } })
  .then((db) => {
    _db = db
    console.log('Connected to MongoDB:', db.s.databaseName)
  })
  .catch((e) => {
    throw e
  })
}

function get () {
  return _db
}

function close () {
  if (_db) {
    console.log('Closing MongoDB connection.')
    _db.close()
  }
}

module.exports = {
  connect,
  close,
  get
}

server.js

'use strict'

const Hapi = require('hapi')

const Db = require('./db')
const _db = Db.get()

const server = new Hapi.Server()

server.connection({
  host: 'localhost',
  port: 8080
})

server.route({
  method: 'GET',
  path: '/',
  handler: (req, rep) => {
    console.log(_db) // _db is undefined
  }
})

Db.connect('mongodb://localhost:27017/test')
.then(() => {
  server.start((err) => {
    if (err) {
      throw err
    }
    console.log(`Server running at: ${server.info.uri}`)
  })
})
.catch((e) => {
  console.error(`${e.name}: ${e.message}`)
  return
})

The problem is that Db.get() return undefined.

Now consider this code instead:

const Db = require('./db')

const server = new Hapi.Server()

...

server.route({
  method: 'GET',
  path: '/',
  handler: (req, rep) => {
    const _db = Db.get()
    console.log(_db) // the _db object exists
  }
})

I don't understand why the first code return undefined as the get() method is called and should store the instance into _db thus accessible in the handler function.

1 Answer 1

1

The value of _db is assigned in a function passed to then of a Promise, the execution of this part is deferred to a point in time until the Promise has been resolved. The server.route is synchronous. It means it will be very likely executed before the Promise has been resolved.

To make it work, wait until the Promise has been resolved:

'use strict'

const MongoClient = require('mongodb').MongoClient

let _db

async function connect (url) {
  try {
    return await MongoClient.connect(url, { server: { poolSize: 5 } })
  } catch (error) {
    throw new Error('Could not connect to Mongo instance');
  }
}

async function get () {
  return _db ? _db : await connect();
}

async function close () {
  if (_db) {
    console.log('Closing MongoDB connection.')
    _db.close()
  }
}

module.exports = {
  connect,
  close,
  get
}

and then

'use strict'

const Hapi = require('hapi')

const Db = require('./db')
const _db = await Db.get()

const server = new Hapi.Server()

server.connection({
  host: 'localhost',
  port: 8080
})

server.route({
  method: 'GET',
  path: '/',
  handler: async (req, rep) => {
    const _db = await Db.get();
    console.log(_db) // _db will be guaranteed to be a valid object, otherwise an error will be thrown
  }
})

Db.connect('mongodb://localhost:27017/test')
.then(() => {
  server.start((err) => {
    if (err) {
      throw err
    }
    console.log(`Server running at: ${server.info.uri}`)
  })
})
.catch((e) => {
  console.error(`${e.name}: ${e.message}`)
  return
})

Read more about async/await there and there.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Rishat. I understand the reason why it is undefined. Though, what is the difference between your async/await code and my last snippet. Just moving const _db = Db.get() in my route handler will work without any other modification. In you code, const _db = await Db.get() is still inside the route handler. Does it mean that the db instance should always be declared like so and there is no way to declare it outside like in my first snippet?
Does it mean that the db instance should always be declared like so --> I mean should be declared in every route handler?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.