75

My code was working before initially but I don't know why it just stopped working and gave me this error:

MongooseError: Operation `users.findOne()` buffering timed out after 10000ms
    at Timeout.<anonymous> (/Users/nishant/Desktop/Yourfolio/backend/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js:184:20)
    at listOnTimeout (internal/timers.js:549:17)
    at processTimers (internal/timers.js:492:7)

I am trying to authenticate the user by login with JWT. My client runs fine but in my backend I get this error. My backend code:

import neuron from '@yummyweb/neuronjs'
import bodyParser from 'body-parser'
import cors from 'cors'
import mongoose from 'mongoose'
import emailValidator from 'email-validator'
import passwordValidator from 'password-validator'
import User from './models/User.js'
import Portfolio from './models/Portfolio.js'
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import auth from './utils/auth.js'

// Dot env
import dotenv from 'dotenv'
dotenv.config()

// Custom Password Specifications
// Username Schema
const usernameSchema = new passwordValidator()
usernameSchema.is().min(3).is().max(18).is().not().spaces()

// Password Schema
const passwordSchema = new passwordValidator()
passwordSchema.is().min(8).is().max(100).has().uppercase().has().lowercase().has().digits().is().not().spaces()

const PORT = process.env.PORT || 5000
const neuronjs = neuron()

// Middleware
neuronjs.use(bodyParser())
neuronjs.use(cors())

// Mongoose Connection
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true }, () => console.log("MongoDB Connected"))

// API Routes
neuronjs.POST('/api/auth/signup', async (req, res) => {
    const { username, email, password, passwordConfirmation } = req.body

    // Validation: all fields are filled
    if (!username || !email || !password || !passwordConfirmation) {
        return res.status(400).json({ 
            "error": "true",
            "for": "fields",
            "msg": "fill all the fields"
        })
    }

    // Validation: username is valid
    if (usernameSchema.validate(username, { list: true }).length !== 0) {
        return res.status(400).json({ 
            "error": "true",
            "for": "username",
            "method_fail": usernameSchema.validate(username, { list: true }),
            "msg": "username is invalid"
        })
    }

    // Validation: email is valid
    if (!emailValidator.validate(email)) {
        return res.status(400).json({ 
            "error": "true",
            "for": "email",
            "msg": "email is invalid"
        })
    }

    // Validation: password is valid
    if (passwordSchema.validate(password, { list: true }).length !== 0) {
        return res.status(400).json({ 
            "error": "true",
            "for": "password",
            "method_fail": passwordSchema.validate(password, { list: true }),
            "msg": "password is invalid"
        })
    }

    // Validation: password is confirmed
    if (password !== passwordConfirmation) {
        return res.status(400).json({ 
            "error": "true",
            "for": "confirmation",
            "msg": "confirmation password needs to match password"
        })
    }

    // Check for existing user with email
    const existingUserWithEmail = await User.findOne({ email })
    if (existingUserWithEmail)
        return res.status(400).json({ "error": "true", "msg": "a user already exists with this email" })

    // Check for existing user with username
    const existingUserWithUsername = await User.findOne({ username })
    if (existingUserWithUsername)
        return res.status(400).json({ "error": "true", "msg": "a user already exists with this username" })

    // Generating salt
    const salt = bcrypt.genSalt()
    .then(salt => {
        // Hashing password with bcrypt
        const hashedPassword = bcrypt.hash(password, salt)
        .then(hash => {
            const newUser = new User({
                username,
                email,
                password: hash
            })
            // Saving the user
            newUser.save()
            .then(savedUser => {
                const newPortfolio = new Portfolio({
                    user: savedUser._id,
                    description: "",
                    socialMediaHandles: {
                        github: savedUser.username,
                        dribbble: savedUser.username,
                        twitter: savedUser.username,
                        devto: savedUser.username,
                        linkedin: savedUser.username,
                    }
                })

                // Save the portfolio
                newPortfolio.save()

                // Return the status code and the json
                return res.status(200).json({
                    savedUser
                })
            })
            .catch(err => console.log(err))
        })
        .catch(err => console.log(err))
    })
    .catch(err => console.log(err))
})

neuronjs.POST('/api/auth/login', async (req, res) => {
    try {
        const { username, password } = req.body

        // Validate
        if (!username || !password) {
            return res.status(400).json({ "error": "true", "msg": "fill all the fields", "for": "fields", })
        }

        const user = await User.findOne({ username })
        if (!user) {
            return res.status(400).json({ "error": "true", "msg": "no account is registered with this username", "for": "username" })
        }
    
        // Compare hashed password with plain text password
        const match = await bcrypt.compare(password, user.password)
    
        if (!match) {
            return res.status(400).json({ "error": "true", "msg": "invalid credentials", "for": "password" })
        }
    
        // Create JWT token
        const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET)
        return res.json({ token, user: { "id": user._id, "username": user.username, "email": user.email } })
    }
    catch (e) {
        console.log(e)
    }
})

// Delete a user and their portfolio
neuronjs.DELETE("/api/users/delete", async (req, res) => {
    auth(req, res)
    const deletedPortfolio = await Portfolio.findOneAndDelete({ user: req.user })
    const deletedUser = await User.findByIdAndDelete(req.user)
    res.json(deletedUser)
})

neuronjs.POST("/api/isTokenValid", async (req, res) => {
    const token = req.headers["x-auth-token"]
    if (!token) return res.json(false)
    
    const verifiedToken = jwt.verify(token, process.env.JWT_SECRET)
    if (!verifiedToken) return res.json(false)
    
    const user = await User.findById(verifiedToken.id)
    if (!user) return res.json(false)

    return res.json(true)
})

// Getting one user
neuronjs.GET("/api/users/user", async (req, res) => {
    auth(req, res)
    const user = await User.findById(req.user)
    res.json({
        "username": user.username,
        "email": user.email,
        "id": user._id
    })
})

// Getting the porfolio based on username
neuronjs.GET("/api/portfolio/:username", async (req, res) => {
    try {
        const existingUser = await User.findOne({ username: req.params.username })
        // User exists
        if (existingUser) {
            const userPortfolio = await Portfolio.findOne({ user: existingUser._id })
            return res.status(200).json(userPortfolio)
        }
        // User does not exist
        else return res.status(400).json({ "error": "true", "msg": "user does not exist" })
    }
    catch (e) {
        console.log(e)
        return res.status(400).json({ "error": "true", "msg": "user does not exist" })
    }
})

// Update Portfolio info
neuronjs.POST("/api/portfolio/update", async (req, res) => {
    auth(req, res)

    // Find the portfolio
    const portfolio = await Portfolio.findOne({ user: req.user })
    // Then, update the portfolio
    if (portfolio) {
        // Call the update method
        const updatedPortfolio = await portfolio.updateOne({
             user: req.user, 
             description: req.body.description, 
             socialMediaHandles: req.body.socialMediaHandles, 
             greetingText: req.body.greetingText, 
             navColor: req.body.navColor, 
             font: req.body.font, 
             backgroundColor: req.body.backgroundColor,
             rssFeed: req.body.rssFeed,
             displayName: req.body.displayName,
             layout: req.body.layout,
             occupation: req.body.occupation
            })
        return res.status(200).json(portfolio)
    }
})

neuronjs.listen(PORT, () => console.log("Server is running on port " + PORT))

The auth.js file function:

import jwt from 'jsonwebtoken'

const auth = (req, res) => {
    const token = req.headers["x-auth-token"]
    if (!token)
        return res.status(401).json({ "error": "true", "msg": "no authentication token" })
    
    const verifiedToken = jwt.verify(token, process.env.JWT_SECRET)
    if (!verifiedToken)
        return res.status(401).json({ "error": "true", "msg": "token failed" })
    
    req.user = verifiedToken.id
}

export default auth

Any help is much appreciated and I have already tried a few solutions like deleting node_modules and re installing mongoose.

yum
  • 1,125
  • 1
  • 8
  • 14

17 Answers17

67

In my experience this happens when your database is not connected, Try checking out following things -

  • Is you database connected and you are pointing to the same url from your code.
  • check if your mongoose.connect(...) code is loading.

I faced this issue where I was running the node index.js from my terminal and mongoose connect code was into different file. After requiring that mongoose code in index.js it was working again.

Abhishek Gangwar
  • 2,168
  • 18
  • 26
18

According to Documentation found in this link: https://mongoosejs.com/docs/connections.html#buffering

Mongoose lets you start using your models immediately, without waiting for mongoose to establish a connection to MongoDB.

That's because mongoose buffers model function calls internally. This buffering is convenient, but also a common source of confusion. Mongoose will not throw any errors by default if you use a model without connecting.

TL;DR:

Your model is being called before the connection is established. You need to use async/await with connect() or createConnection(); or use .then(), as these functions return promises now from Mongoose 5.

Nafis Abdullah Khan
  • 2,062
  • 3
  • 22
  • 39
11

I had the same issue when using Mongoose 6. I connected to Mongoose in my index.js file the following way:

mongoose.connect(
  process.env.MONGO_URL,
  { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true },
  () => {
    console.log('Connected to MongoDB');
  }
);

I found the following info for Mongoose 6 in their site:

useNewUrlParser, useUnifiedTopology, useFindAndModify, and useCreateIndex are no longer supported options. Mongoose 6 always behaves as if useNewUrlParser, useUnifiedTopology, and useCreateIndex are true, and useFindAndModify is false. Please remove these options from your code.

When I removed the useCreateIndex: true option the issue was solved.

Simeon Stoykov
  • 891
  • 7
  • 11
  • This worked for me. Do you have any idea why `useCreateIndex: true` causes trouble? – nick Jan 14 '22 at 13:41
  • 1
    It caused trouble, because is not a supported option in Mongoose 6 and it shouldn't be added in the options (like the quote in the answer says), but we had it in the options. – Simeon Stoykov Jan 20 '22 at 12:39
  • If you add the callback to mongoose.connect, you will get the error, 'Mongoose.prototype.connect() no longer accepts a callback.' – passion Jun 09 '23 at 13:09
7

Allow Network Access from everywhere.

Please note that this is a temporary solution.

What this error is trying to say is that it cannot access the MongoDB collection. This may be because of these 3:

  1. Your IP address is not allowed to access the database
  2. You don't have an internet connection
  3. Other problem
Gabriel Arghire
  • 1,992
  • 1
  • 21
  • 34
  • 3. Other problem. – Sergo Jul 20 '23 at 18:33
  • 1
    Thank you! Updated answer. – Gabriel Arghire Jul 21 '23 at 08:03
  • In my case, it was an issue with database, but not with database's connection. The connection was good. I used session to check if the user was autenticated or not, but not used callback with returning session in auth options. And as I was using auth.js package, it connected with my database to check the session, which not returned, cause I didn't remember to use callback. This was my other problem :) – Sergo Jul 21 '23 at 17:47
4

I've run into this a number of times; particularly when I've upgraded nested dependancies that require mongoose. This always does the trick for me.

rm -rf node_modules
rm package-lock.json
npm install --package-lock-only
npm install
jwerre
  • 9,179
  • 9
  • 60
  • 69
  • I didn't add the 3rd step, but this was the only thing that worked for me. Apparently, when I tried npm audit fix, I messed something up with mongoose. Thanks for the trick. – isaacsan 123 May 03 '21 at 11:49
  • 1
    If you remove your `package-log.json` you should reinstall it with `npm install --package-lock-only`. Occasionally, two separate npm install will create package locks that cause merge conflicts in source control systems. – jwerre May 03 '21 at 21:39
4

My code worked normaly from one PC but from another one I got the same error. I have MongoDB free hosting by https://www.mongodb.com/ .

I fixed it by adding my current IP to Security - Network Access - IP Access List in the hosting server.

Banana Cake
  • 1,172
  • 1
  • 12
  • 31
  • Crawling internet speed or the inability of your server to connect to a remote database could also be the reason for the error. – Collins USHI Sep 15 '21 at 18:54
4

I think the reason is that your IP address is not whitelisted for your db. Check for it if you have a problem like this.

Gor
  • 79
  • 4
1

It worked for me after I used this code, in my app.js file:

mongoose.connect(process.env.DATABASE_URI, () => {
    console.log("Mongo connected");
});

And removed all the four mongoose options below from my code:

{
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true,
    useFindAndModify: false,  
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
1

If you are trying to run the project from another network or Ip, make sure you whitelist your ip in mongoDB atlas. Simply go to Network tab> Add ip address.

0

After Creating Cluster click connect and add your IP or add another IP in the MongoDB Atlas

0

I had the same problem. In my case, I had kept mongoose.connect statement in a different file and forgot to invoke it while writing the require statement.

require(./services/mongoose);

I had done this in my index.js file and changed it to this

require(./services/mongoose)();
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
yeti
  • 1
  • 1
0

There was already a Cluster , collection made in my mongo db atlas , all i had to do was clear that out and send another post request to make it work .

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
0

I just had this issue myself when I tried to use my database while my server was in error and mongoose created a huge 87 part error panel that I had to sift through and when I did, I found that the options that I passed to mongoose were depreciated. So if you can scroll to where you start your server, you may see details telling you to remove or append certain options. Removing the extra options fixed my issue.Photographic evidence of my issue and where I found it in the terminal

0

Make sure that you're connecting to MongoDB at the top of your function(inside file) and doing (CRUD) operations after connecting to MongoDB Atlas.

Hope that makes sense. I was getting error because in my file I'm loading data from other server and inserting into my MongoDB after that asynchronous operations I'm connecting to my MongoDB Server, that's why I was getting error.

CORRECT

await mongoose.connect(MONGO_URL, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
}); 
await parseAndLoadPlanetsData();

INCORRECT

await parseAndLoadPlanetsData();
await mongoose.connect(MONGO_URL, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
zaib
  • 59
  • 2
  • 3
0

If you are importing the database connect string from .env file, make sure that the .env file is in the root folder where you are running the npm run command.

I've tried all the solutions here to no awail. Suddenly I realized that the .env file was in /server folder, which is one folder deeper than my project root folder.

Make sure you move .env file to project root folder!! To get the process.env.DB_CONNECT for example.

CrmXao
  • 937
  • 2
  • 16
  • 19
-1

This error[user.findOne()] showing because your config package version is updated automatically.

Enter the following in your terminal:

npm i -E config@3.3.1

or

yarn add -E config@3.3.1
bguiz
  • 27,371
  • 47
  • 154
  • 243
-2

mongoose.connect('mongodb://localhost/myapp', {useNewUrlParser: true});

Just do this add {useNewUrlParser: true} in connection file.

Zsolt Meszaros
  • 21,961
  • 19
  • 54
  • 57