AWS Lambda can't access mongoDB - node.js

I'm deploying simple express CRUD API with serverless framework. It works fine until it comes to accessing databese, it returns {"message":"Internal Server Error"}. But when running locally it works as intended. Is there a problem with the way I'm connecting to mongoDB?
const mongoose = require("mongoose");
const { logger } = require("../Log/pino");
require("dotenv").config();
mongoose.set('strictQuery', false);
mongoose.connect(process.env.MONGO_URI, {serverSelectionTimeoutMS: 5000});
const connection = mongoose.connection
.once("open", () => {
logger.info("connected to database");
})
.on("error", (err) => {
logger.info(`mongoose error: ${err}`);
});
module.exports = connection;

Fixed it. Problem was that I was only allowing access to mongoDB cluster to requests sent only from my IP. Changed cluster network access settings and it works now as it should.

Related

Cannot connect to mongoDB Atlas using mongoose : { MongoNetworkError: failed to connect to server }

Although I am not the first on Stackoverflow not to be able to connect to mongoDB atlas using mongoose, no one seems to have my specific error:
{ MongoNetworkError: failed to connect to server
[cluster0-shard-00-00-shqnc.mongodb.net:27017] on first connect
[MongoNetworkError: connection 5 to
cluster0-shard-00-00-shqnc.mongodb.net:27017 closed]
Here's how my server is set-up:
Keys.js
module.exports = {
mongoURI:
"mongodb+srv://Ahmed:<MyMongoDBAtlasPWD>#cluster0-shqnc.mongodb.net/test?retryWrites=true&w=majority"
};
Server.js
const express = require("express");
const mongoose = require("mongoose");
const app = express();
// DB Config
const db = require("./config/keys").mongoURI;
// Connect to MongoDB
mongoose
.connect(db, {
useNewUrlParser: true
})
.then(() => {
console.log("MongoDB connected!");
})
.catch(err => {
console.log(err);
});
app.get("/", (req, res) => {
res.send("Hello");
});
//process.env.Port is for Heroku
const port = process.env.Port || 5000;
// `` ES6 Template literal is used so that we can put a variable inside the String
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
And this is the code suggested by the MongoDB atlas website to be used:
const MongoClient = require('mongodb').MongoClient;
const uri = "mongodb+srv://Ahmed:<password>#cluster0-shqnc.mongodb.net/test?retryWrites=true&w=majority";
const client = new MongoClient(uri, { useNewUrlParser: true });
client.connect(err => {
const collection = client.db("test").collection("devices");
// perform actions on the collection object
client.close();
});
But, since I don't want to use mongoClient but rather mongoose, I am having some trouble and I cannot see why the code doesn't work;
EDIT 1: I have managed to connect using the Shell command(Check-out my answer). However, connecting through the app doesn't work and gives a different error:
{ MongoNetworkError: failed to connect to server
[cluster0-shard-00-01-shqnc.mongodb.net:27017] on first connect
[MongoError: bad auth Authentication failed.]
EDIT 2: I made a stupid mistake. I've forgotten to remove <> from the . All is good now.
The problem is that I was trying to connect using my MongoDB Atlas account password instead of the user password. Yes, those are 2 different things.
1. Click on Database Access
2. Edit the current user and modify the password
3. Use that password to connect to MongoDB Atlas
Make sure you have whitelisted your public IP. You can find that by googling "what is my ip".

nodejs+mongodb native driver+ExpressJS Rest API- connect once and reuse design suggestion [duplicate]

This question already has answers here:
How to properly reuse connection to Mongodb across NodeJs application and modules
(25 answers)
Closed 3 years ago.
I am learning to use the mongodb native driver along with nodeJS and ExpressJS. I am new to NodeJS so please bear with me.
The UI CLIENT sends data to the REST API endpoint and the POST call inserts the data (document) into MongoDB collection.
When I am going through the examples at MongoDB native driver documentation, I notice that collection.insertOne, collection.save are always performed as a callback to the mongo_client.connect. I don't understand this because I want to connect to mongo_client once and continue to update the collection and bring down the connection (mongo_client.close) when the express server is brought down. I understand that callbacks are safe.
const client = new MongoClient(url, {useNewUrlParser: true});
// Use connect method to connect to the server
client.connect(function(err) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
insertDocuments(db, function() {
client.close();
});
});
Why do I have to connect for every CRUD operation? save the state of the connection to the db/collection and cannot reuse?
My existing code:
const express = require('express')
const app = express()
const server_port = 64726
const MongoClient = require('mongodb').MongoClient;
const insert_user = (id, email)=> {
mongo_client.connect(err => {
console.log("mongo connect function called....")
assert.equal(null, err)
console.log ("connected successfully to DB ")
const mongo_user_collection = mongo_client.db(mongo_db_name).collection("users");
mongo_user_collection.save ({'_id':id,'email':email,'lastlogin': new Date() })
// perform actions on the collection object
// mongo_client.close();
});
}
app.post ('/api/login/verify', (req, res) => {
insert_user(req.body.id,req.body.email);
})
app.listen(server_port, ()=>{
console.log('Server started...')
})
In my code, I see for every post call I need to connect and then insert the document. How to avoid this behavior so I can Connect once, reuse connection and insert docs for every POST call?
This worked for me. Thanks all for the suggestions.
const mongo_client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
let mongo_user_collection;
mongo_client.connect(err => {
console.log("mongo connect function called....")
assert.equal(null, err)
console.log ("connected successfully to DB ")
mongo_user_collection = mongo_client.db(mongo_db_name).collection("users");
});
const insert_user = (id, email)=> {
mongo_user_collection.save ({'_id':id,'email':email,'lastlogin': new Date() })
}
app.post ('/api/login/verify', (req, res) => {
insert_user(req.body.id,req.body.email);
})
app.listen(server_port, ()=>{
console.log('Server started...')
})

How to connect to a MongoDB database from an application deployed on ZEIT Now?

I have deployed an application on Zeit Now using ExpressJS. The application makes a connection to MongoDB using Mongoose. However, the state of the connection, which I obtain using mongoose.connection.readyState is displayed as 2, which denotes 'connecting'.
I tried running the application locally and it works fine, where I am able to write to the database.
const connectionURL = "mongodb+srv://MONGODB_USERNAME:MONGOD_BPASSWORD#cluster1-23abc.mongodb.net/DATABASE_NAME?retryWrites=true"
expressApp.listen(3000, function() {
console.log("Listening to port 3000");
});
mongoose
.connect(
connectionURL, { useNewUrlParser: true }
)
.then(function() {
console.log("db connected!");
});
expressApp.get("/", function(req, res) {
res.write(`Connection State: ${mongoose.connection.readyState}\n`);
res.end();
});
I would expect mongoose.connection.readyState to be 1, which denotes 'connected'.
However, mongoose.connection.readyState is stuck at 2, which denotes 'connecting'.
Also, now logs does not show any errors.
You'll want to cache your MongoDB connection so you won't have to make a new connection on each lamda call.
You can make an lib folder and empty mongoose.js file (lib/mongoose.js) as I did and place this code inside:
`import mongoose from 'mongoose';
let cachedDb = null;
console.log('outside-cachedDB:', cachedDb);
async function connectToDatabase(uri) {
if (cachedDb) {
console.log('=> using cached database instance');
return cachedDb;
}
// If no connection is cached, create a new one
const db = await mongoose.connect(uri, { useNewUrlParser: true });
console.log('New MongoDB Connected');
// Cache the database connection and return the connection
cachedDb = db;
return db;
}
export default async () => {
await connectToDatabase(process.env.MONGODB_URI);
};`
Then call this custom mongoose function in any lamda that needs a mongoDB connection:
`import express from "express";
import mongoose from "../lib/mongoose";
const app = express();
// #route Get api/connect
// #desc Tests post route
// #access Public
app.get("*", async (req, res) => {
await mongoose();
// Code to query your DB or whatever here
});
export default app;`
You don't have to use express of course, but I personally haven't moved on to newer solutions. One of these days I'll learn micro.js.

mLab doesn't work on Heroku

I've added mLab to my Heroku app, I also use mongoose. I tried use connection string from localhost, and it was working(almost). In my server file I use:
var db = mongoose.connection;
if (process.env.MONGODB_URI) {
mongoose.connect('mongodb://heroku_fb82r7lw:bbgj8uliam1psdda88fleu55li#ds161580.mlab.com:61580/heroku_fb82r7lw');
// mongoose.connect(process.env.MONGODB_URI);
} else {
mongoose.connect('mongodb://heroku_fb82r7lw:bbgj8uliam1psdda88fleu55li#ds161580.mlab.com:61580/heroku_fb82r7lw');
// mongoose.connect('mongodb://localhost/fitMe')
}
If I open the app from localhost, it saves things to the db, and can get it back, although not everything, but on heroku it doesn't work at all. I use react with server. I think that something wrong with the routs.. so here is the link to server file :
https://github.com/HelenaVolskaia/Motivation/blob/master/server/app.js
You can set an env variable locally and only use this:
// Connect Mongo
mongoose.Promise = global.Promise; // mongoose promises deprecated, use node - mongoosejs.com/docs/promises
mongoose.connect(config.db.MONGODB_URI);
mongoose.connection.once('open', () => { console.log('MongoDB Connected'); });
mongoose.connection.on('error', (err) => { console.log('MongoDB connection error: ', err); });
But regardless, add the on connection error handler and see what the error is, so you can dig deeper into why it's not connecting.

Mongoose never returns its promise when I try to connect to the same db using a working URL

I have a locally hosted mongodb that I can connect to using mongodb.MongoClient.
Working code:
var mongoClient = require("mongodb").MongoClient;
...
var startApp = function(db) {
// Get our collections in an easy to use format
var database = {
chats: db.collection('chats'),
messages: db.collection('messages')
};
// Configure our routes
require('./app/routes')(app, database);
// START APP
// Start app on port
app.listen(port);
// Tell user the app is running
console.log("App running on port " + port);
// Expose app
exports = module.exports = app;
}
// DATABASE
var database = null;
mongoClient.connect(config.url, function(err, returnDB) {
if(err) {
console.log(err);
} else {
console.log("DB connected");
startApp(returnDB);
}
});
Legacy code that no longer works:
var mongoose = require('mongoose');
...
// Connect to DB
console.log('Connect to database (' + db.url + ')');
mongoose.connect(db.url);
I have added a callback to this connect method but it never gets called (error or no error, this connect function never gets to my callback).
This entire legacy app relies on the API using mongoose to talk to the database so I do not want to redo it all using mongodb. How can I fix this?
*config.url and db.url are loaded from the same file and it is a valid and running mongodb.
It was really easy to fix. Thanks #Bhavik for asking me what version I was using.
I updated mongoose to 4.8.1 by specifying the newest version in packages.json and the issue is resolved.

Resources