Search code examples
javascriptnode.jstypescriptmongodbexpress

client undefined, can't connect to database with mongodb driver


I have a node app and when I add my routes: app.use('/api', routes), the app crashes, without this line the app runs.

The error is: return db.collection(name) ^ TypeError: Cannot read properties of undefined (reading 'collection')

because db is undefined.

index.ts:

import express from 'express'
import cors from 'cors'
import routes from './routes'
import { connectDB } from './db'
const port= process.env.port|| 5000
const app = express()

app.use(cors())
app.use(express.json())
app.use('/api', routes)
app.get('/', (req, res) => res.send('Running'))    

connectDB().then(res => {
    app.listen(port, () => console.log(`Running: http://localhost:${port}`))
}).catch(err => console.log(err))

db.ts:


let db: Db
    
export const connectDB = async (): Promise<void> => {
  try {
    const uri = process.env.MONGO_URI as string
     const client = new MongoClient(uri)
    await client.connect()   
    db = client.db(process.env.DB_NAME)
  }catch(error) {
    console.log(error)
    
  }
}

export const getCollection = <T extends Document>(name: string): Collection<T> => {
  return db.collection<T>(name)
}

'/routes/index.ts':

import { Router } from 'express'
import productRoutes from './products/productRoutes'

const router = Router()

router.use('/products', productRoutes )

export default router

productRoutes.ts:

import express from 'express'
import { createProduct } from '../../agents/product/productAgent';

router.post('/', async (req, res) => {
    try {
      const success = await createProduct(req.body);
      res.status(success ? 201 : 400).json({ success });
    } catch (error: any) {
      res.status(500).json({ error: error.message });
    }
  })

productAgent.ts:

import { getCollection } from '../../db'
import { ObjectId } from 'mongodb'
import { IProduct } from '../../types/IProduct'

const collectionProduct = getCollection<IProduct>('products')

export const createProduct = async (parameters: IProduct): Promise<boolean> => {
    try {
     const res= await collectionProduct.insertOne(parameters)
     return res.acknowledged
    } catch (error) {
        throw new Error('Error create product')
    }
}

I can't figure out what's wrong and how adding 'app.use('/api', routes)' to my main file affects my database connection.


Solution

  • how adding 'app.use('/api', routes)' to my main file affects my database connection.

    Because the database connection hasn't been established (i.e. db = client.db(process.env.DB_NAME) hasn't run yet) at the time you end up calling getCollection<IProduct>('products') (which happens when you import { createProduct } from '../../agents/product/productAgent';).

    The simplest fix is to move that const collectionProduct = getCollection<IProduct>('products') into the createProduct function.