1

Previously I had a working, single-file, application that was essentially:

const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server);
app.set('socketio', io);

import { MongoClient } from 'mongodb';

var mongo_client;

var connection_string = 'mongodb://localhost:27017' // for local development environment 

MongoClient.connect(connection_string, (err, client) => {
  if (err) {
    throw err;
  } else {
    mongo_client = client;
  }
});

/*

lots of middleware and route handling

*/

server.listen(PORT, () => {
  console.log(`running on port ${PORT}`);
});

In middleware, within the same file, I would make a call to the database with something like:

var collection = mongo_client.db('users').collection('users');

var query = { };

var options = { };

  try {
    var user = await collection.findOne(query, options);
    return user;
  } catch (err) {
    console.log('error: ' + err);
  }

I'm in the process of refactoring and have put the MongoClient.connect() block in its own file.

config/database.js now looks like:

const MongoClient = require('mongodb').MongoClient;

const { connection_string } = require('./environment_variables');

let mongo_client;

MongoClient.connect(connection_string, (err, client) => {
  if (err) {
    throw err;
  } else {
    mongo_client = client;
    console.log('FIRST:  mongo_client: ');
    console.log(mongo_client);
  }
});

console.log('SECOND:  mongo_client: ');
console.log(mongo_client);

module.exports = mongo_client;

To begin testing how to import it into another file, I am doing this in app.js:

const mongo_client = require('./config/database');

app.get('/', async (req, res) => {
  const query = { username: 'my name' };
  const collection = mongo_client.db('users').collection('users');   // <----- error is here, mongo_client is undefined    
  const result = await collection.findOne(query);
  res.json({ result: result });
});

(note, when I better understand how all this works, I will move the route and middleware handling out of app.js)

The console logs are:

SECOND:  mongo_client:
undefined
FIRST:  mongo_client:
MongoClient {
// ... lots of mongodb client properties here  
}
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'db' of undefined

So it seems like MongoClient.connect() is asynchronous and therefore mongo_client is not defined before I try and call mongo_client.db('users').collection('users').

My questions are:

  • How can this issue be resolved?
  • Why wasn't it happening before I extracted MongoClient.connect() out of app.js?

I've been reading articles like these:

MongoClient connection pooling

MongoClient docs

But they seem to either:

  • Include subsequent calls to the database within the MongoClient.connect() function block (and i can't wrap my whole app within that function) OR
  • They call app.listen() within the MongoClient.connect() function block (and this is also not feasible as I do several things with express() and http and socket.io)

Environment:

node v14.18.1  
"mongodb": "^4.1.4" (native driver)

Edit:

I tried the following changes in config/database.js per this article.

I replaced this:

const MongoClient = require('mongodb').MongoClient;

const { connection_string } = require('./environment_variables');

let mongo_client;

MongoClient.connect(connection_string, (err, client) => {
  if (err) {
    throw err;
  } else {
    mongo_client = client;
  }
});
module.exports = mongo_client;  

with this:

const MongoClient = require('mongodb').MongoClient;

const { connection_string } = require('./environment_variables');

const mongo_client = new MongoClient(connection_string);

const is_this_the_right_thing_to_do = async () => {
  await mongo_client.connect();
};

is_this_the_right_thing_to_do();

module.exports = mongo_client;

The error went away and it is returning a result, but I am not sure if this is the correct way to do it.

Also, I am not sure how I can use the single instance of mongo_client in all routes and middleware. I tried requiring it at the top of app.js, hoping that the routes and middleware (in other files) that were required afterwards would have access to it, but they don't, this was the error in the route middleware:

UnhandledPromiseRejectionWarning: ReferenceError: mongo_client is not defined

Another edit:

I've posted an answer on someone else's question here which may be what I am looking for, will update this post after further testing.

user1063287
  • 10,265
  • 25
  • 122
  • 218

1 Answers1

0

If you are trying to access database (mongo_client.db("your database name here") in your case) from other routes then you can maybe try something like this in your app.js or index.js.

const connectDB = async () => {
  await client.connect();
  db = client.db("greendeckData");
  app.use((req, res, next) => {
    req.db = db;
    next();
  });
  app.use("/get", getRouter);
};

You can check the source from where I found the solution link, here

Vaibhav Bisht
  • 87
  • 2
  • 14