#node.js #mongodb #docker #mongoose
Вопрос:
Итак, вот что я пытаюсь сделать. Я создал службу MongoDB с помощью docker и пытаюсь подключить свой проект NodeJS к службе базы данных с помощью мангуста. Вот мой 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
Я открыл панель mongo-express, и все работает нормально. Теперь вот мое приложение NodeJS, используемое MongoClient
для подключения к базе данных и вставки фиктивной записи.
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)
})
Все по — прежнему в порядке. Приложение успешно вставило запись в базу данных mongo. Однако все не работает, когда я пытался использовать Mongoose
вместо MongoClient
этого . Вот мой фрагмент кода для 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)
})
Это приводит меня к ошибке Cannot connect to the database: Authentication failed.
. Есть какие-нибудь идеи о том, как решить эту проблему?
Пожалуйста, обратите внимание: я запускаю приложение node на своей физической машине, а не внутри контейнера, используя изображение. Я попытался localhost:27017
заменить его именем службы, например, mongodb://admin:password@mongodb/office
но это тоже не работает. Он возвращает следующую ошибку Cannot connect to the database: getaddrinfo EAI_AGAIN mongodb
Комментарии:
1. Что говорят журналы mongo о неудачной аутентификации?
2. Есть идеи, где я могу найти эти журналы?
3.
docker logs mongodb
=)4. Вот журнал из docker MongoDB — pastebin.com/raw/zctjbQLG
5. А, вот этот. Пожалуйста, добавьте «?authSource=администратор» в URL мангуста: mongoosejs.com/docs/connections.html#connection-string-options Монго недавно изменил формат URL-адреса. Часть пути URL — адреса обычно была именем базы данных, но, начиная с версии 4, это имя базы данных аутентификации. Контейнер создает пользователя в
admin
базе данных, и собственный клиент использует его по умолчанию. В URL Мангуста вы добавили${db_name}
. Ошибка в журналах немного более ясна:Could not find user "admin" for db "office"
Ответ №1:
TL;DR вам необходимо указать базу данных аутентификации в mongooseUrl как ?authSource=admin
или как {authSource:"admin"}
в connectOptions
.
Объяснения
Образ docker регистрирует MONGO_INITDB_ROOT_USERNAME
пользователя в базе данных аутентификации по умолчанию admin
.
Эта база данных используется по умолчанию, если не указано в URI. На мой вкус, логика излишне сложна, и документация об этом недостаточно ясна:
/defaultauthdb
Необязательный. База данных аутентификации для использования, если строка подключения содержит имя пользователя:пароль@ учетные данные для аутентификации, но параметр authSource не указан.
Если и authSource, и defaultauthdb не указаны, клиент попытается аутентифицировать указанного пользователя в базе данных администратора.
Недостающий бит заключается в том, что /defaultauthdb
раньше /database
эта версия оставалась в документации мангуста.
Параметр служит 2 целям, и это вызывает путаницу. В нем указывается база данных по умолчанию, в которой вы храните свои коллекции, и база данных проверки подлинности по умолчанию, в которой Mongo ищет пользователей. Значения по умолчанию могут быть перезаписаны параметрами URI:
Источник аутентификации — База данных, используемая при аутентификации с пользователем и передаче. В MongoDB пользователи привязаны к базе данных. Если вы получаете неожиданный сбой входа в систему, вам может потребоваться установить эту опцию.
Имя базы данных — Указывает, к какой базе данных подключаться, и переопределяет любую базу данных, указанную в строке подключения. Это полезно, если вы не можете указать базу данных по умолчанию в строке подключения, как с некоторыми
Источник аутентификации — База данных, используемая при аутентификации с пользователем и передаче. В MongoDB пользователи привязаны к базе данных. Если вы получаете неожиданный сбой входа в систему, вам может потребоваться установить эту опцию.