7

throw new MongooseError('Query.prototype.exec() no longer accepts a callback');
          ^
 
MongooseError: Query.prototype.exec() no longer accepts a callback

I was trying to register users.

double-beep
  • 5,031
  • 17
  • 33
  • 41

12 Answers12

18

I had this same issue and fixed it with two solutions:

  1. Downgrade your Mongoose. The latest versions stopped accepting callbacks. I personally downgraded to v6.10.0
npm uninstall mongoose
npm install mongoose@6.10.0
  1. Change the callback function to a then/catch methods or use async/await. So for example, instead of:
myModel.find({}).exec((err, res) => {
  //callback code
});

Just remove your .exec() function and replace it with .then()/.catch():

myModel.find({}).then((res) => {
  //if succeded do this block of code
}).catch((err) => {
  //catch error
});
3

Just replace your existing code with this solution, and it will work.

Everyone is getting this error, and this is happened just because of the version change in mongoDB. Here below, I will put some steps and follow it, and it will work perfectly then.

  1. Install mongoose again in your current terminal of your project. Check the version of mongoose in dependencies of package.json file before and after executing this. You will realise that now the latest version is install in your project.

npm install mongoose

  1. The error is showing that mongoose is "no longer accepts a callback". So, with the help of .then and .catch we can resolve it.

import MongoStore from 'connect-mongo';

mongoose.connect("mongodb+srv://:@cluster0.igegl4n.mongodb.net/?retryWrites=true&w=majority", {useNewUrlParser: true, useUnifiedTopology: true } )

.then(() => console.log('Connected Successfully'))

.catch((err) => { console.error(err); });

Run your code now you can connect with the database successfully.

If you are using other methods such as findById, findByIdAndUpdate, findByIdAndDelete, find, and any other, then just you just need to add .then() after this method.

Like this,

List.find().then(function(lists){

//Return results

})

Vinit Dabhi
  • 993
  • 8
  • 8
2

Mongoose released version 7.0, where they dropped support of callbacks just in a click :( https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md

So, every other module depending on it (passport-local-mongoose in my case) went south too. Rollback to mongoose 6.10 (at least temporally) to fix it.

2

Check your package.json. If it contains the latest version of mongoose (i.e "mongoose": "^7.0.0") then use this to fix it:

mongoose
    .connect('mongodb://127.0.0.1:27017/test')
    .catch (error => console.log(error));
Elmar B.
  • 750
  • 4
  • 14
1

I resolved the issue by replacing my callback function in my db.js file by an other.

My new db.js to connect Mongo data base :

const mongoose = require('mongoose')

const connectDB = async () => {
    try {
        mongoose.set('strictQuery', false)
        mongoose.connect(process.env.MONGO_URI) 
        console.log('Mongo connected')
    } catch(error) {
        console.log(error)
        process.exit()
    }
}

module.exports = connectDB

    
Shadou
  • 11
  • 2
1

latest version of mongoose is not supporting callback functions . so I have uninstalled it and then installed the previous version and it worked for me.

  1. npm uninstall mongoose
  2. npm install mongoose@6.10.0
0

Same here. I guess you are also doing the same course (Angela Yu). If so, I fixed the issue by not using the passport-local-mongoose module but the passport-local long way instead. I could have used the old version of Mongoose to fix it but I decided to use the latest version and fix it by replacing the callback with promises (then) in Passport-local code (from documentation). Here is my code (app.js):

const express=require("express")
const app=express()
const ejs=require("ejs")
const mongoose=require("mongoose")
const bcrypt=require("bcrypt")
const session=require("express-session")
const passport=require("passport")
const LocalStrategy=require("passport-local").Strategy;
app.use(express.urlencoded({extended:false}))  //Not using bodyParser, using Express in-built body parser instead
app.set("view engine","ejs")
app.use(express.static("public"))

app.use(session({
    secret:"Justarandomstring.",
    resave:false,
    saveUninitialized:false
}))

app.use(passport.initialize());
app.use(passport.session());

mongoose.connect("mongodb://127.0.0.1:27017/userDB")
const userSchema= new mongoose.Schema({
    username : String,
    password : String
})

const User=new mongoose.model("User",userSchema)

//Creating Local Strategy. passport-local-mongoose 3 lines of code for Strategy, 
//Serialiazation, Deserialization not working due to recent changes in Mongoose 7
passport.use(new LocalStrategy((username,password,done)=>{  //done is a callback function
    try{
        User.findOne({username:username}).then(user=>{
            if (!user){
                return done(null,false, {message:"Incorrect Username"})
            }
 //using bcrypt to encrypt passoword in register post route and compare function in login post round. 
 //login post route will check here during authentication so need to use compare here  
            bcrypt.compare(password,user.password,function(err,result){ 
                if (err){
                    return done(err)
                }

                if (result) {
                    return done(null,user)
                }
                else {
                    return done (null,false, {message:"Incorrect Password"})
                }
            })

        })
    }
    catch (err){
            return done(err)
    }

}))
//serialize user
passport.serializeUser(function(user, done) {
    done(null, user.id);
  });
  
//deserialize user  
passport.deserializeUser(function(id, done) {
    console.log("Deserializing User")
    try {
        User.findById(id).then(user=>{
            done(null,user);
        })
    }
    catch (err){
        done(err);
    }
  });


//get routes
app.get("/",function(req,res){
    res.render("home")
})

app.get("/login",function(req,res){
    res.render("login")
})

app.get("/register",function(req,res){
    res.render("register")
})

app.get("/secrets",function(req,res){
    if (req.isAuthenticated()){
        res.render("secrets")
    }
    else {
        res.redirect("/login")
    }
})

app.get("/logout",function(req,res){
    req.logout(function(err){
        if(err){
            console.log(err)
        }
        res.redirect("/");
    });
    
})

//post routes
app.post("/register",function(req,res){
    bcrypt.hash(req.body.password,10,function(err,hash){  //10 is SaltRounds
        if (err){
            console.log(err)
        }
        const user= new User ({
            username:req.body.username,
            password:hash
        })
        user.save()

        passport.authenticate('local')(req,res,()=>{res.redirect("/secrets")}) 
    })
})   
    


app.post('/login', passport.authenticate('local', { successRedirect:"/secrets", failureRedirect: '/login' }));

//listen
app.listen(3000, ()=> {
    console.log("Server Running on Port 3000")
})

I know the Local Strategy, Serialization, Deserialization is too long compared to 3 lines of code in passport-local-mongoose but got hang of it now and I have no issue using this long way too.

0

I had a similar problem, but when using Model.find((err, data) => ); syntax, the error was like "MongooseError: mongoose.prototype.connect() no longer accepts a callback."

It was solved by creating an async function, calling find() on the model, and then returning the data I got from it. I hope the code snippet helps you with your project.

Context: I had a Person model and wanted to execute the find() operation on it.

getAllPeople = async () => {
    const data = await Person.find({});
    return data;
};

getAllPeople().then((data) => {
    console.log(data);
});
Het Modha
  • 51
  • 1
  • 3
0

Upgrading and adopting the latest practices is necessary. Eventually we will have to upgrade and then adopt the new way. So why not do it now?

Here's the link to documentation of mongoose

The following worked for me

  • server.js - In your server.js file, you can connect to your MongoDB database using Mongoose with the following code:
const mongoose = require('mongoose');

// Your MongoDB connection URI
const uri = 'your-mongodb-uri';

mongoose.connect(uri, {
  serverSelectionTimeoutMS: 5000
}).catch(err => console.log(err.reason));

In this code snippet, the serverSelectionTimeoutMS option is set to 5000 milliseconds (5 seconds). This option determines the maximum time to wait for the MongoDB server to be selected or connected. If the server is not selected within the specified timeout, an error will be thrown.

  • package.json - Additionally, make sure your package.json file includes the "mongoose" dependency with a version that supports the serverSelectionTimeoutMS option. For example:
"dependencies": {
  "mongoose": "^7.2.0"
}

In case you also want to start mongo locally

  • Start docker mongo database
# Ensure that docker is installed
$ docker run -d  --name mongo-on-docker  -p 27888:27017 -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=secret mongo

## So you connection string would become
## var dbUrl = 'mongodb://mongoadmin:secret@127.0.0.1:27888'
codeaprendiz
  • 2,703
  • 1
  • 25
  • 49
0

The same error was appearing to me, the error was like "MongooseError: mongoose.prototype.connect() no longer accepts a callback." I resolved the issue by replacing my callback function

Old code

mongoose.connect(process.env.DATABASE, {
    useNewUrlParser: true,
    useUnifiedTopology: true
}, () => {
    console.log("Database connected");
});

New Code

mongoose.connect(process.env.DATABASE, {
    useNewUrlParser: true,
    useUnifiedTopology: true
},).then((res) => {
    console.log("Database connected");
  }).catch(error => {
     console.log(error);
   });
Saurabh
  • 76
  • 5
-1

What was causing this problem for me was that the npm package 'mongoose-unique-validator' was not working with the most recent Mongoose 7.0.

However, ChatGpt told me that I can do without the validator, and in my model where I call it at the bottom, I can use the following piece of code.

userSchema.index({ email: 1 }, { unique: true });

Everything works fine.

-2

The same error was appearing to me, the problem I found my one of the login routes was that I haven't declared next() parameter to the function.

Previous code:

router.post('/login', passport.authenticate('local', { failureFlash: true, failureRedirect: '/login' }), (req, res) => {
    req.flash('success', 'Welcome to Yelp Camp!');
    res.redirect('/campgrounds');
})

Final Code:

router.post('/login', (req, res, next) => {
    passport.authenticate('local', { 
      failureFlash: true, 
      failureRedirect: '/login' 
    })(req, res, next);
    res.redirect('/campgrounds');
  });
Michael M.
  • 10,486
  • 9
  • 18
  • 34
Dhiraj
  • 1