Reputation: 1964
So, here is what I'm trying to do. I have created a MongoDB service using docker and trying to connect my NodeJs project to the database service using mongoose. Here is my docker-compose.yaml
version: '3'
services:
mongodb:
container_name: mongo_database
image: mongo
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
networks:
- mongo-compose-network
ports:
- '27017:27017'
mongo-express:
container_name: mongo_express
image: mongo-express
restart: unless-stopped
depends_on:
mongodb:
condition: service_started
networks:
- mongo-compose-network
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_SERVER=mongodb
ports:
- '8081:8081'
networks:
mongo-compose-network:
driver: bridge
I have open the mongo-express panel and everything is working fine. Now, Here is my NodeJs app using MongoClient
to connect to the database and insert a dummy record.
require('dotenv').config();
// required modules
const mongoose = require("mongoose")
const MongoClient = require('mongodb').MongoClient;
// database config
const db_name = process.env.DB_NAME || "office"
const mongoUrl = process.env.MONGO_URL || `mongodb://admin:password@localhost:27017`
const mongooseUrl = process.env.MONGO_URL || `${mongoUrl}/${db_name}`
// database connection and sample document
const connectOptions = { useNewUrlParser: true, useUnifiedTopology: true }
const document = {
"name": "John Doe",
"employee_id": Math.floor(Math.random() * 1000)
}
MongoClient.connect(mongoUrl, connectOptions).then((client)=> {
client.db(db_name).collection("users").insertOne(document).then(()=> {
console.log("Document Inserted")
process.exit(1)
})
}).catch((e) => {
console.log(`Cannot connect to the database: ${e.message}`)
process.exit(1)
})
Everything is still fine. The application has successfully inserted the record in the mongo database. However, things are not working when I tried to use Mongoose
instead of MongoClient
. Here is my code snippet for Mongoose
.
require('dotenv').config();
// required modules
const mongoose = require("mongoose")
const MongoClient = require('mongodb').MongoClient;
// database config
const db_name = process.env.DB_NAME || "office"
const mongoUrl = process.env.MONGO_URL || `mongodb://admin:password@localhost:27017`
const mongooseUrl = process.env.MONGO_URL || `${mongoUrl}/${db_name}`
// database connection and sample document
const connectOptions = { useNewUrlParser: true, useUnifiedTopology: true }
const document = {
"name": "John Doe",
"employee_id": Math.floor(Math.random() * 1000)
}
mongoose.connect(mongooseUrl, connectOptions).then((connection) => {
connection.collection('users').insert(document);
}).catch((e) => {
console.log(`Cannot connect to the database: ${e.message}`)
process.exit(1)
})
It's giving me the error Cannot connect to the database: Authentication failed.
. Any ideas on how to resolve this issue?
Please note: I am running my node app in my physical machine, not inside a container using an image. I tried replacing the localhost:27017
with the service name such as mongodb://admin:password@mongodb/office
but it doesn't work either. It returns the following error Cannot connect to the database: getaddrinfo EAI_AGAIN mongodb
Upvotes: 1
Views: 2070
Reputation: 37048
TL;DR you need to specify authentication database in the mongooseUrl as ?authSource=admin
or as {authSource:"admin"}
in connectOptions
.
Explanations
The docker image registers the MONGO_INITDB_ROOT_USERNAME
user in the default authentication database admin
.
This database is being used by default unless specified in the URI. The logic is unnecessarily complicated to my taste and the documentation isn't clear enough about it:
/defaultauthdb
Optional. The authentication database to use if the connection string includes username:password@ authentication credentials but the authSource option is unspecified.
If both authSource and defaultauthdb are unspecified, the client will attempt to authenticate the specified user to the admin database.
The missing bit is that the /defaultauthdb
used to be /database
- this version remains in mongoose documentation.
The parameter serves 2 purposes and this causes confusion. It specifies the default database where you store your collections and the default authentication database where Mongo looks-up users. Defaults can be overwritten by URI parameters:
authSource - The database to use when authenticating with user and pass. In MongoDB, users are scoped to a database. If you are getting an unexpected login failure, you may need to set this option.
dbName - Specifies which database to connect to and overrides any database specified in the connection string. This is useful if you are unable to specify a default database in the connection string like with some
authSource - The database to use when authenticating with user and pass. In MongoDB, users are scoped to a database. If you are getting an unexpected login failure, you may need to set this option.
Upvotes: 7