Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to connect to MongoDB using Node.js written in TypeScript?

I'm working on a Node.js server, connecting to MongoDB and written with TypeScript. When I try to use MongoDB it doesn't create a connection, however when I check the mongo output it does appear to create a connection.

What am I missing in my code to define the connection in Node.js?

My connection string is 'mongodb://localhost:27017'

My connection method:

connect() {
    console.log('connecting to mongo') //this is called
    MongoClient.connect(this.connectionString, {useNewUrlParser: true})
    .then(client => {
        console.log('setting client'); //this doesn't get called
        this.client = client;
        console.log(this.client);
    })
    .catch(error => {
        console.log('error during connecting to mongo: '); //this also doesn't get called
        console.error(error);
    });
}

Mongo output:

2018-11-08T23:06:24.106+0100 I NETWORK [listener] connection accepted from 127.0.0.1:51345 #11 (2 connections now open)

2018-11-08T23:06:24.107+0100 I NETWORK [conn11] received client metadata from 127.0.0.1:51345 conn11: { driver: { name: "nodejs", version: "3.1.9" }, os: { type: "Darwin", name: "darwin", architecture: "x64", version: "17.7.0" }, platform: "Node.js v8.9.3, LE, mongodb-core: 3.1.8" }

My repository is at https://github.com/FrisoDenijs/MEAN-ToDo/blob/master/server/src/db/mongo.db.ts for the full code.

console.log(db) as asked by shkaper

MongoClient {
  domain: null,
  _events: {},
  _eventsCount: 0,
  _maxListeners: undefined,
  s:
   { url: 'mongodb://localhost:27017',
     options:
      { servers: [Array],
        caseTranslate: true,
        useNewUrlParser: true,
        socketTimeoutMS: 360000,
        connectTimeoutMS: 30000,
        promiseLibrary: [Function: Promise] },
     promiseLibrary: [Function: Promise],
     dbCache: {},
     sessions: [] },
  topology:
   Server {
     domain: null,
     _events:
      { serverOpening: [Function],
        serverDescriptionChanged: [Function],
        serverHeartbeatStarted: [Function],
        serverHeartbeatSucceeded: [Function],
        serverHeartbeatFailed: [Function],
        serverClosed: [Function],
        topologyOpening: [Function],
        topologyClosed: [Function],
        topologyDescriptionChanged: [Function],
        commandStarted: [Function],
        commandSucceeded: [Function],
        commandFailed: [Function],
        joined: [Function],
        left: [Function],
        ping: [Function],
        ha: [Function],
        authenticated: [Function],
        error: [Function],
        timeout: [Function],
        close: [Function],
        parseError: [Function],
        open: [Object],
        fullsetup: [Object],
        all: [Object],
        reconnect: [Function] },
     _eventsCount: 25,
     _maxListeners: Infinity,
     clientInfo:
      { driver: [Object],
        os: [Object],
        platform: 'Node.js v8.9.3, LE' },
     s:
      { coreTopology: [Object],
        sCapabilities: null,
        clonedOptions: [Object],
        reconnect: true,
        emitError: true,
        poolSize: 5,
        storeOptions: [Object],
        store: [Object],
        host: 'localhost',
        port: 27017,
        options: [Object],
        sessionPool: [Object],
        sessions: [],
        promiseLibrary: [Function: Promise] } } }
like image 227
Friso Avatar asked Jan 01 '23 15:01

Friso


2 Answers

The issue is because mongo.connect is async code and controller call it wrongly. so the subsequent line mongo.getDb() will be executed without having this.client initiated properly.

Since you use Typescript, we can use async/await for cleaner code.

async connect() { // add async
    console.log('connecting to mongo');

    try {
      if (!this.client) { // I added this extra check
        console.log('setting client');
        this.client = await MongoClient.connect(this.connectionString, { useNewUrlParser: true })
        console.log(this.client);      
      }
    } catch(error) {
      console.log('error during connecting to mongo: ');
      console.error(error);
    }    
}

And in controller code

async get(req: Request, res: Response) { // add async
  const mongo = new MongoDb();
  await mongo.connect(); // add await
  const db = mongo.db(); 
  // ....     
}

I tried your repo with the changes and got this response

enter image description here

Hope it helps

like image 160
deerawan Avatar answered Jan 05 '23 16:01

deerawan


Based on what you said about neither error nor success callbacks being called, I think the problem is not only in code here: https://github.com/FrisoDenijs/MEAN-ToDo/blob/master/server/src/db/mongo.db.ts But also e.g. here: https://github.com/FrisoDenijs/MEAN-ToDo/blob/master/server/src/controllers/to-do.controller.ts When you run mongo.connect there should be an option to wait for the promise returned from MongoClient.connect. So I would change code in mongo.db.ts to for example sth like this (it depends how you want to handle this promise):

connect() {
    console.log('connecting to mongo')
    return MongoClient.connect(this.connectionString, {useNewUrlParser: true})
    .then(client => {
        console.log('setting client');
        this.client = client;
        console.log(this.client);
    })
    .catch(error => {
        console.log('error during connecting to mongo: ');
        console.error(error);
    });
}

Then in to-do.controller.ts you can await this or use then:

get(req: Request, res: Response) {
    const mongo = new MongoDb();
    mongo.connect().then(() => {

      const db = mongo.getDb();
      const collection = db.collection('todo', (error, collection) => {
          if (error) {
              res.json(error);
              res.statusCode = HttpStatus.BAD_REQUEST
              return;
          }

          collection.find().toArray((error, result) => {
              if (error) {
                  res.json(error);
                  res.statusCode = HttpStatus.BAD_REQUEST
              }

              res.json(result);
              res.statusCode = HttpStatus.OK;
          })

      });

      mongo.close();
    });
} 

I suppose that your code just does not "wait" for connection to be established and then fails.

like image 22
barnski Avatar answered Jan 05 '23 18:01

barnski