1

Solution Provided in the End

This is my app.js code

const express = require("express");
const mongoose = require("mongoose");
const app = express();

app.set("view engine", "ejs");
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static("public"));

mongoose.connect("mongodb://localhost:27017/todolistDB");

const itemsSchema = {
    name: String,
};

const Item = mongoose.model("Item", itemsSchema);

const item1 = new Item({
    name: "Drink Water",
});

const item2 = new Item({
    name: "Go for a run",
});

const defaultItems = [item1, item2];

// Item.insertMany(defaultItems)

const listSchema = {
    name: String,
    items: [itemsSchema],
};

const List = mongoose.model("List", listSchema);

app.get("/", async function (req, res) {
    let allItems;
    try {
        allItems = await Item.find();
    } catch (err) {
        console.log(err);
    }
    console.log(allItems);
    return res.render("i");
});

app.post("/", async function (req, res) {
    let item = new Item({
        name: req.body.newItem.trim(),
    });
    let listName = req.body.list;
    if(listName === "today"){
        item.save();
        return res.redirect("/");
    }
    let foundList = await List.findOne({name: listName}).exec();
    foundList.items.push(item);
    foundList.save();
    return res.redirect("/"+listName);
});

app.post("/delete", async function (req, res) {
    let id = req.body.checkbox;
    let listName = req.body.listName.toLowerCase();
    if(listName === "today"){
        try {
            const item = await Item.findByIdAndDelete(id);
        } catch (err) {
            console.log(err);
        }
        return res.redirect("/");
    }
    let foundList = await List.findOne({name: listName}).exec();
    foundList.items.pull({_id: id});
    foundList.save();
    return res.redirect("/"+listName);
});

app.get("/:listName", async function (req, res) {
    let { listName } = req.params;
    if(listName.toLowerCase() == "delete"){
        return res.redirect("/");
    }

    let foundList = await List.findOne({name: listName.toLowerCase()}).exec();

    if(!foundList){
        const list = new List({
            name: listName,
            items: [],
        });  
        list.save();
        foundList = list;
    }

    return res.render("list", {
        listTitle: listName,
        items: foundList.items,
    });
});

app.listen(3000, function () {
    console.log("Server started on port 3000");
});


This is my package.json code

{
...
  "dependencies": {
    "ejs": "^3.1.9",
    "express": "^4.18.2",
    "mongoose": "^7.3.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}

Node and npm version:

node -v
v18.16.1

npm -v
8.13.2

There was absolutely no problem connection to localhost mongodb, until I tested one of my apps on Atlas cluster, and updated node.js to v18.16.1. Now the connection gets established and the code works perfectly fine when using Atlas cluster, but it is not working for localhost anymore.

I'm using nodemon so I can also continuously track errors. Initially I'm getting the following error when starting *localhost:3000: on my browser:

MongooseError: Operation `items.find()` buffering timed out after 10000ms
    at Timeout.<anonymous> (D:\Projects\to-do-list\node_modules\mongoose\lib\drivers\node-mongodb-native\collection.js:185:23)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7)
undefined
D:\Projects\to-do-list\node_modules\mongoose\lib\drivers\node-mongodb-native\collection.js:185
          const err = new MongooseError(message);
                      ^

MongooseError: Operation `lists.findOne()` buffering timed out after 10000ms
    at Timeout.<anonymous> (D:\Projects\to-do-list\node_modules\mongoose\lib\drivers\node-mongodb-native\collection.js:185:23)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7)

Node.js v18.16.1

When I modified the code to write something to the database instead of reading with Item.find() in app.get("/"), I'm getting the following error:

D:\Projects\to-do-list\node_modules\mongoose\lib\model.js:3237
        for (let i = 0; i < error.writeErrors.length; ++i) {
                                              ^

TypeError: Cannot read properties of undefined (reading 'length')
    at D:\Projects\to-do-list\node_modules\mongoose\lib\model.js:3237:47

I tried console logging the mongodb connection status using console.log(mongoose.connection.readyState) and its giving the value 2 which meaning Connecting.

After waiting for a while without exiting the nodemon terminal, I'm getting the following error:

D:\Projects\to-do-list\node_modules\mongoose\lib\connection.js:792
    err = new ServerSelectionError();
          ^

MongooseServerSelectionError: connect ECONNREFUSED ::1:27017
    at _handleConnectionErrors (D:\Projects\to-do-list\node_modules\mongoose\lib\connection.js:792:11)
    at NativeConnection.openUri (D:\Projects\to-do-list\node_modules\mongoose\lib\connection.js:767:11) {
  reason: TopologyDescription {
    type: 'Unknown',
    servers: Map(1) {
      'localhost:27017' => ServerDescription {
        address: 'localhost:27017',
        type: 'Unknown',
        hosts: [],
        passives: [],
        arbiters: [],
        tags: {},
        minWireVersion: 0,
        maxWireVersion: 0,
        roundTripTime: -1,
        lastUpdateTime: 20551391,
        lastWriteDate: 0,
        error: MongoNetworkError: connect ECONNREFUSED ::1:27017
            at connectionFailureError (D:\Projects\to-do-list\node_modules\mongodb\lib\cmap\connect.js:370:20)
            at Socket.<anonymous> (D:\Projects\to-do-list\node_modules\mongodb\lib\cmap\connect.js:293:22)
            at Object.onceWrapper (node:events:628:26)
            at Socket.emit (node:events:513:28)
            at emitErrorNT (node:internal/streams/destroy:151:8)
            at emitErrorCloseNT (node:internal/streams/destroy:116:3)
            at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
          cause: Error: connect ECONNREFUSED ::1:27017
              at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) {
            errno: -4078,
            code: 'ECONNREFUSED',
            syscall: 'connect',
            address: '::1',
            port: 27017
          },
          [Symbol(errorLabels)]: Set(1) { 'ResetPool' }
        },
        topologyVersion: null,
        setName: null,
        setVersion: null,
        electionId: null,
        logicalSessionTimeoutMinutes: null,
        primary: null,
        me: null,
        '$clusterTime': null
      }
    },
    stale: false,
    compatible: true,
    heartbeatFrequencyMS: 10000,
    localThresholdMS: 15,
    setName: null,
    maxElectionId: null,
    maxSetVersion: null,
    commonWireVersion: 0,
    logicalSessionTimeoutMinutes: null
  },
  code: undefined
}

I have tried starting the mongodb server both from Compass and mongosh.

MongoDB Compass


When I tried checking which app/services are using the port "27017", I found all the PID mentioned point to Compass only:

Check port usage

port 27100

port 26840

port 28668


Even telnet on localhost 27017 was successful

enter image description here

enter image description here


I have tried:

  • Deleting the node_modules package and *.json files, and reinstalling all dependencies.
  • Uninstalling and reinstalling mongodb.
  • Restarting Compass.
  • Restarting system.
  • Starting server from Compass
  • Starting server from mongosh

The main problem here seems to be MongoDB not connecting or refusing to connect: MongooseServerSelectionError: connect ECONNREFUSED ::1:27017, as timeout and other errors won't even occur if it had been successfully connected.

Please help me fix this the error

Soution

The problem turned out to be localhost using ipv6 address, and MongoDB running on ipv4.

Some solutions that I found are:

  • Adding a family: 4 option as mongoose.connect("mongodb://localhost:27017/todolistDB",{family: 4});. This tells the localhost to use ipv4.
  • Running mongod --ipv6 on terminal. Localhost uses ipv6 so this --ipv6 enables ipv6 access for mongodb.
  • Replacing localhost in mongoose.connect("mongodb://localhost:27017/todolistDB"); with 127.0.0.1 ad mongoose.connect("mongodb://127.0.0.1:27017/todolistDB");. 127.0.0.1 is the localhost ipv4 address. ::1 is the localhost ipv6 address
  • Use node v16
PrathamJ
  • 162
  • 12

0 Answers0