"Mongo Error : Authentication failed" can't read datas from MongoDB Atlas - node.js

Today I wanted to use clusters in MongoDB Atlas to get an online DB, instead of my MongoDB local database (which worked perfectly fine),
So, I followed a mLab tutorial,
It works perfectly on writing in the database (when I auth in my website, it adds the datas in the database, when I write a message in the chat it adds the message, etc...)
But when I want to read these datas, I got :
MongoTimeoutError: Server selection timed out after 30000 ms
MongoError: Authentication failed
The connect in my server/index.js seems to work, because I got the console log :
mongoose
.connect(
`mongodb+srv://${process.env.USER}:${process.env.PASSWORD}#ofilms-demo-f9iwz.mongodb.net/test?retryWrites=true&w=majority`,
{ useNewUrlParser: true, useUnifiedTopology: true }
).then(() =>
console.log(
"working"
)
)
.catch(err => console.log(err));
but not other routes, like this one (which get all users in the database) :
const mongo = require("mongodb").MongoClient;
router.get("/getAll", function(req, res) {
console.log("get all users");
const client = new mongo(`mongodb+srv://${process.env.USER}:${process.env.PASSWORD}#ofilms-demo-f9iwz.mongodb.net/test?retryWrites=true&w=majority`, {
useNewUrlParser: true,
useUnifiedTopology: true
});
client.connect(err => {
const collection = client.db("test").collection("users");
collection.find().toArray((err, items) => {
res.json(items);
});
client.close();
});
});
One model from Mongoose :
/* eslint-disable no-undef */
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true,
lowercase: true
},
password: {
type: String,
required: true
},
firstname: String,
lastname: String,
sexe: String,
mobilePhone: String,
departement: Number,
city: String,
moviesLiked: Array,
seriesLiked: Array,
moviesDisliked: Array,
seriesDisliked: Array,
moviesFavorites: Array,
seriesFavorites: Array,
lists: Array,
creationDate: {
type: Date,
default: Date.now
},
lastConnection: Date,
isVerified: Boolean,
isAdmin: Boolean,
isModerator: Boolean,
isConnected: Boolean
});
module.exports = User = mongoose.model("users", UserSchema);
I can show you the code of other files if needed, or give you the link of the repo if someone wants it, but it's a really big project,
Thanks,

You seem to connect mongodb with both mongoose.connect() and MongoClient.connect(), one of them will be enough.
If you want to use mongoose you can connect to mongodb in your main file (index.js or app.js), and when connected to the db your server can start listening.
And you don't need to connect mongodb in your routes.
For example:
index.js (main file)
const express = require("express");
const app = express();
require("dotenv").config();
const users = require("../routes/users"); //todo: correct the users route path
app.use("/api/users", users);
mongoose
.connect(
`mongodb+srv://${process.env.USER}:${process.env.PASSWORD}#ofilms-demo-f9iwz.mongodb.net/test?retryWrites=true&w=majority`,
{ useNewUrlParser: true, useUnifiedTopology: true }
)
.then(() => console.log("working"))
.catch(err => console.log(err));
in your route: (users.js)
const express = require("express");
const router = express.Router();
const User = require("../../models/User");
router.get("/users", async (req, res) => {
const users = await User.find({});
res.send(users);
});
module.exports = router;
As you see there is no connection related code in our route, because we have already connected when the application starts.
For this code to work, you need to add your local IP to the IP whitelist IP in mongodb atlas panel. (SECURITY --> Network Access --> IP Whitelist.
Also the user you are using to connect must have read an write priveleges.
You can check your users priveleges in SECURITY --> Database Access --> MongoDB Users.

Related

How to fetch all data only from mongoose with Nodejs

I am not able to fetch all the data from mongoose. When I tried to fetch data it create new collection name(signins) with empty, but singin collection already exists.
I don't understand what I am doing wrong here
Index.js File
const express = require("express");
const app = express();
const mongoose = require("mongoose");
mongoose
.connect("mongodb://0.0.0.0:27017/signin")
.then(() => console.log("MongoDB Connected"))
.catch((err) => console.log(err));
const User = require("./models/signin");
app.use("/", (req, res) => {
User.find({}, (err, data) => {
if (err) throw new err();
return res.json(data);
});
});
app.listen(5500, () => console.log("Port Started on 5500"));
signin
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const loginSign = new Schema({
email: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
});
module.exports = Users = mongoose.model("signin", loginSign);
Mongoose will automatically "pluralize" the name of your collection from your model name.
So mongoose.model("signin", loginSign) is creating a collection named "signins".
From the documentation: https://mongoosejs.com/docs/models.html#compiling
The first argument is the singular name of the collection your model is for. Mongoose automatically looks for the plural, lowercased version of your model name.
Providing a third argument will use a collection name you specify, instead of the one mongoose creates. So in your case you could:
mongoose.model("signin", loginSign, "signin");
That said, having plural collection names is the standard, and encouraged.

Mongoose Connection with MongoDB

I've been working with Mongoose/MongoDB and I realized I don't quite understand how the connection between mongoose and my MongoDB database persists. Let's say I have Node application with a server.js file.
const express = require('express')
const dotenv = require('dotenv')
dotenv.config()
const connectDB = require('./config/db')
connectDB()
const app = express()
app.get('/', (req, res) => {
res.send('API is running...')
})
const PORT = process.env.PORT || 5000
app.listen(
PORT,
console.log(`Server running in ${process.env.NODE_ENV} port ${PORT}`)
)
And then I have my database configuration file where the connection is initiated.
const mongoose = require('mongoose')
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true,
})
console.log(`MongoDB Connected: ${conn.connection.host}`)
} catch (error) {
console.error(`Error: ${error.message}`)
process.exit(1)
}
}
module.exports = connectDB
My question is, after the database is connected with mongoose.connect(), how does it persist throughout the rest of the application? Obviously, this allows me to interact with the database in other files, but I'm not quite clear on what's going on "underneath the hood". Let's say I have a Product model
const mongoose = require('mongoose')
const reviewSchema = mongoose.Schema(
{
name: { type: String, required: true },
rating: { type: Number, required: true },
comment: { type: String, required: true },
},
{
timestamps: true,
}
)
const productSchema = mongoose.Schema(
{
user: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
name: { type: String, required: true },
image: { type: String, required: true },
brand: { type: String, required: true },
category: { type: String, required: true },
description: { type: String, required: true },
reviews: [reviewSchema],
rating: { type: Number, required: true, default: 0 },
numReviews: { type: Number, required: true, default: 0 },
price: { type: Number, required: true, default: 0 },
countInStock: { type: Number, required: true, default: 0 },
},
{
timestamps: true,
}
)
const Product = mongoose.model('Product', productSchema)
module.exports = Product
I can then have a route
router.get(
'/',
asyncHandler(async (req, res) => {
const products = await Product.find({})
res.json(products)
})
)
Which would operate on this Product model. My question is, how is mongoose aware of the database still (after the initial connection) that allows it to call methods on this Model that allow it to interact with the database.
I'm not an expert in MongoDB nor JavaScript but I think that you might have misunderstood some concepts.
Mongoose as it says on its website provides a schema-based solution module to your application data.
You use mongoose to connect with the database through its methods, the database is not connected with mongoose.
Dotenv file basically stores your server configuration data within your project
separating it from the code that allows you to display port info, processes etc in a clear way.
Let's start reviewing the first file
Here you create some const of express and dotenv
const express = require('express')
const dotenv = require('dotenv')
After that, you apply the config method to the dotenv const (you can also add that method at the first line)
dotenv.config()
Now you create the connectDB const loading the content from the DB file (which I suppose it's the next one)
const connectDB = require('./config/db')
Calling the method of the class starts the connection with the Database:
connectDB()
Now you use express to make a get request that will be displayed on your root folder and basically will display some basic data from the port and the process (loaded from ENV file)
const app = express()
app.get('/', (req, res) => {
res.send('API is running...')
})
const PORT = process.env.PORT || 5000
app.listen(
PORT,
console.log(`Server running in ${process.env.NODE_ENV} port ${PORT}`)
)
Let's review now the other file.
You create a const from mongoose
const mongoose = require('mongoose')
And establish a connection to your DB
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true,
})
console.log(`MongoDB Connected: ${conn.connection.host}`)
} catch (error) {
console.error(`Error: ${error.message}`)
process.exit(1)
}
}
This is the important part, you export that const to the whole project so it can be accessed from different parts of the project that's the reason that allows you to connect with the DB without providing the same credentials every single time, and the same logic applies to dotenv file
module.exports = connectDB
((If you're not familiar with Java just ignore this:))
I was working today with MySQL and Java JDBC API and I created some files that allow me to interact with the DB like you're doing with Mongoose, see:
//variables to get DB info and connection
private Connection connection;
private PreparedStatement stmt = null;
private ResultSet rs = null;
private Statement statement = null;
//Constructor, when you create an object of this class will establish a connection
with the dbCredentials variables (like dotenv)
public DevOps() throws SQLException {
this.connection = DriverManager.getConnection(dbCredentials.getDbname(), dbCredentials.getUsername(), dbCredentials.getPass());
}
This would be like your dotenv file, you just have to change the data here instead of changing lots of lines of code when you migrate your DB or update credentials
public class dbCredentials {
public final static String username = "user";
public final static String pass = "password";
public static String dbname = "jdbc:mysql://192.168.56.1/school";
public static String allowMultiQueries() {
return dbname+"?allowMultiQueries=true";
}
public static String getUsername() {
return username;
}
public static String getPass() {
return pass;
}
public static String getDbname() {
return dbname;
}
}
And you basically just have to do this:
DevOps devops = new DevOps();
which would be similar to:
const connectDB = require('./config/db')
So basically the concept of all of this is to keep your code organized, ofc you can have all of that on a single file but in terms of scalability would be painful to maintain especially when you have to apply any change to your DB.
Hope this was useful for you, just ask me if you have any doubt!

How does mongoose know what collection I am accessing?

I'm having a trouble grasping a concept in Mongoose.
I'm using MongoDB atlas, got a cluster , a database and 2 collections.
users, characters.
Through a guide I've learned that a good way to write your stuff is to have a model (I use the naming schema) as a file, importing it into your Database module/class
and using it there to perform a query...
const mongoose = require("mongoose");
const process = require("./config.env");
db = () => {
return mongoose
.connect(process.env.URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: true,
})
.then((response) => {
console.log(`Connected to Databse : ${response.connection.host}`);
})
.catch((err) => {
console.log("DB_ERROR:", err);
process.exit(1);
});
};
module.exports = db;
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
});
const User = mongoose.model("User", UserSchema);
module.exports = User;
const User = require("../schemas/User");
const db = require("../config/db");
class Database {
constructor(db, collection) {
this.db = db;
this.collection = collection;
this.User = User;
}
connect() {
return db();
}
}
module.exports = Database;
one file to handle the db connection..another file as the User schema and a third file to handle every function i might use globally...
One thing I cannot wrap my mind around is
how is the findOne() function able to locate the collection I am using without me telling it what collection i want it to search in?
is it somehow translating the
const User = mongoose.model("User", UserSchema);
line and searching for "users" as well? I just can't understand the magic behind this...
what if I want to search specifically in the characters collection...?
Mongoose uses the model name, as passed when it was created: mongoose.model("User", UserSchema), converted to lower case and with an 's' appended.
For the model User it uses the collection users by default. You can change this by explicitly specifying the collection name in the schema.

Can't upload a document to my mongoDB server

I am studying on my own node.js and I am following codewithmosh website.
The thing is, is that I try to upload a new object to my mongo database using compass.
I have the following code (see screenshots for outputs) and there is no error and on mosh'es tutorial everything is working great.
The problem I have is that my server isn't being updated with the new document.
Any idea what I am missing?
I refreshed the compass a few times and nothing changes.
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true , useUnifiedTopology: true}).then(() =>
console.log('connected to MongoDB')
).catch((err) => console / log('Could not connect to MongoDB', err));
const courseSchema = new mongoose.Schema({
name: String,
author:String,
tags: [String],
date: {type: Date, default: Date.now},
isPublished: Boolean
})
const Course = mongoose.model('Course', courseSchema);
async function createCourse () {
const course = new Course ({
name: 'node.js Course',
author: 'Daniel',
tags: ['node', 'backend'],
isPublished: true,
});
const result = await course.save();
console.log(result);
}
createCourse();
OK I figure it out.
There was a bad configuration in my compass.
I had to go to setup a connection

How to connect to specific database with Mongoose and node?

I'm learning how to use Mongoose and there's something I don't understand - how can I connect to specific database and collection in my cluster?
I have 5 different databases and each database have few different collections
When I was using pure Mongo client - the way the show it in official documentation, I connected like that:
const MongoClient = require('mongodb').MongoClient;
const uri = process.env.mongo_connection_string;
const client = new MongoClient(uri, { useNewUrlParser: true });
client.connect(err => {
const collection = client.db("database_name").collection("collection_name");
// Do some work here in the selected database and the selected collection
client.close();
});
Now I want to use Mongoose to practice. So in my app.js to establish the connection I do:
mongoose.connect(process.env.mongo_connection_string , {useNewUrlParser: true})
.then( () => console.log("Connection established"))
.catch(err => console.log(err))
Then I have created a schema for one of the objects I want to store in the database.
const mongoose = require('mongoose')
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
}
})
const User = mongoose.model('User', UserSchema)
module.exports = User
How do I associate this model with the database and the collection I need?
To connect to a specific database you can add the name in the options like this:
mongoose
.connect(db_url, {
useNewUrlParser: true,
useUnifiedTopology: true,
dbName: 'MyDatabaseName',
})
.then(() => {
console.log('Connected to the Database.');
})
.catch(err => console.error(err));
Please specify the database name in URI like link (or)
Please get the default client object with mongo URI then get the required database and collection objects.

Resources