javascriptmongodbtypeerrorurimongodb-compass

Javascript, MongoDB context -- TypeError: Cannot read properties of undefined (reading 'collection')


I recently came across the error popping up in terminal or command prompt mentioned in the question above.

Exact error shown is:

const taskCollection = db.collection('tasks');
                              ^

TypeError: Cannot read properties of undefined (reading 'collection')
    at Command.<anonymous> (C:\Abc\xyz\Task-Manager-CLI-Project\index.js:50:31)
    at Command.listener [as _actionHandler] (C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:494:17)
    at C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:1296:65
    at Command._chainOrCall (C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:1193:12)
    at Command._parseCommand (C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:1296:27)
    at C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:1082:27
    at Command._chainOrCall (C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:1193:12)
    at Command._dispatchSubcommand (C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:1078:25)
    at Command._parseCommand (C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:1264:19)
    at Command.parse (C:\Abc\xyz\Task-Manager-CLI-Project\node_modules\commander\lib\command.js:910:10)

This is a simple task manager CLI project. I have connected mongoDB with my project, still it shows the same error and I am not getting where the error is? How do I solve it Here are my 2 code files:

db.js

const { MongoClient } = require('mongodb');
const uri = 'mongodb://localhost:27017';

//we have used MongoDB Node.js driver to connect js to MongoDB database.

const client = new MongoClient(uri)

let db;

async function connect(){
    try{
        await client.connect();
        db = client.db('task_manager_db'); 
        
        // it is selecting the database named 'taskmanager'. If the specified database does not exist, MongoDB will create it when you first write data to it.
        //now variable db holds the reference to 'taskmanager' database
        
        console.log('Connected to the database');
    } catch(err){
        console.log('Error connecting to the database...', err);
    }
}

function getDB(){
    return db;
}

module.exports = {connect, getDB};

index.js

//using commander.js library for the project
//commander.js library provides functions that can run the project on CLI mode.
//Which is the ultimate aim and learning behind the project: To create and run a project using CLI.

const program = require('commander');

//importing the functions from db.js
const {connect, getDB} = require('./db');

program
.version('1.0.0')
.description('Task Manager CLI')
//connecting MongoDB database (i.e. to the uri to be specific)
.action(connect());

//general structure of defining commands for CLI using commander.js library
// program
// .command('')
// .description('')
// .action(//function inside() => { });

//command to list all tasks --> list
program
.command('list')
.description('list of commands')
.action(async() => {
    //extract database from function
    const db = getDB();
    //refer to the collection in db
    const taskCollection = db.collection('tasks');

    try{
        const tasks = await taskCollection.find().toArray();
        console.log("Listing all the tasks:");
        tasks.forEach((task_) => {
            console.log(`- ${tasks.task_}`);
        });
    }catch(err){
        console.log("Error displaying tasks...");
    }

});

//command to add a task --> add <taskname>
program
.command('add <taskname>')
.description('Add a new task')
.action(async() => {
    const db = getDB();
    const taskCollection = db.collection('tasks');

    try{
        const result = await taskCollection.insertOne({ taskname });
        console.log(`New Task added: ${task} TaskID: ${result.insertedId}`);
    }catch(err){
        console.log("Error adding task...", err);
    }
});

//command to delete task --> delete <TaskId>
program
.command("delete <TaskId>")
.description("Delete a task")
.action(async() => {
    const db = getDB();
    const taskCollection = await db.collection('tasks');

    try{
        const result = await tasksCollection.deleteOne({ _id: new ObjectId(TaskId) });
        console.log(`Deleted Task (ID: ${TaskId}`);
    }catch(err){
        console.log("Error deleting a task...", err);
    }
});

program.parse(process.argv);
  1. I tried changing the URI from my MongoDB compass, even renamed it from "New Connection" TO "Project1" then copied the URI to db.js file. Didn't work.

  2. I tried changing the URI from mongodb://localhost:27017 to mongodb://localhost:27018 OR from mongodb://localhost:27017 to mongodb://localhost:27017/Project1 still didn't work. The error still pops.

Expected output is the commands list, add , delete should run on command prompt and show the coded console.log() outputs or error handling outputs. Instead it says the collection tasks of my database task_manager_db is undefined and hence cannot read its properties.


Solution

  • Since connect() is an asynchronous function, you should return db within that function itself and use await in your index.js file like this:

    db.js

    const { MongoClient } = require('mongodb');
    const uri = 'mongodb://localhost:27017';
    const client = new MongoClient(uri)
    
    let db;
    
    async function connect(){
        try{
            await client.connect();
            db = client.db('task_manager_db'); 
            return db;
        } catch(err){
            console.log('Error connecting to the database...', err);
        }
    }
    
    module.exports = {connect};
    

    index.js

    const program = require('commander');
    const {connect} = require('./db');
    
    program
    .version('1.0.0')
    .description('Task Manager CLI');
    
    program
    .command('list')
    .description('list of commands')
    .action(async() => {
        const db = await connect();
        const taskCollection = db.collection('tasks');
    
        try{
            const tasks = await taskCollection.find().toArray();
            console.log("Listing all the tasks:");
            tasks.forEach((task_) => {
                console.log(`- ${tasks.task_}`);
            });
        }catch(err){
            console.log("Error displaying tasks...");
        }
    
    });
    
    program
    .command('add <taskname>')
    .description('Add a new task')
    .action(async() => {
        const db = await connect();
        const taskCollection = db.collection('tasks');
    
        try{
            const result = await taskCollection.insertOne({ taskname });
            console.log(`New Task added: ${task} TaskID: ${result.insertedId}`);
        }catch(err){
            console.log("Error adding task...", err);
        }
    });
    
    program
    .command("delete <TaskId>")
    .description("Delete a task")
    .action(async() => {
        const db = await connect();
        const taskCollection = await db.collection('tasks');
    
        try{
            const result = await tasksCollection.deleteOne({ _id: new ObjectId(TaskId) });
            console.log(`Deleted Task (ID: ${TaskId}`);
        }catch(err){
            console.log("Error deleting a task...", err);
        }
    });
    
    program.parse(process.argv);