NodeJS MongoDB Times Out Loading Route - node.js

I am having troubles after moving all of my Controllers Routes and Models into their own files. I seem to only get a timeout when loading anything from the database and none of my console.log()'s run anymore, The model works and it posts the testPost (in the controller) perfectly fine. I tried adding the testPost because console.log() or errors aren't showing in my console.
Controller
//jshint esversion: 6
const mongoose = require('mongoose');
const Post = require(`./../models/posts`);
//Initial Post to posts Model
const testPost = new Post ({
postTitle: `Default Post`,
postDate: Date.now(),
postBody: `If you're seeing this, It means your DB is connected and you're ready to go!`,
postAuthor: `Admin`
});
const defaultPost = [testPost];
//View Single Post
exports.showOne = function(req, res){
const requestedPostTitle = req.params.id;
Post.findOne({postTitle: requestedPostTitle}, function(err, foundPost){
if (!err && foundPost){
const title = foundPost.postTitle;
const date = foundPost.postDate;
const content = foundPost.postBody;
const author = foundPost.postAuthor;
res.render(`./post/post`, {
title: title,
date: date,
content:content,
author:author
});
}
});
};
Model
//jshint esversion: 6
const mongoose = require(`mongoose`);
const postSchema = new mongoose.Schema ({
{SCHEMA DATA}
}
});
module.exports = mongoose.model(`Post`, postSchema);
exports.databaseName = `postsDB`;
index.js Routes
app.get(`/posts`, postPages.showAll);
app.get(`/post/:id`, postPages.showOne);
app.get(`/post/compose`, postPages.compose);
app.post(`/post/compose`, postPages.create);

Firstly I moved my database startup into it's own file called db.js as per this great article that was referenced to me by another SO user:
https://theholmesoffice.com/mongoose-connection-best-practice/
After moving the configurations into db.js I logged the errors as per the article:
// If the connection throws an error
mongoose.connection.on('error',function (err) {
console.log('Mongoose default connection error: ' + err);
});
I had not realised that I wouldn't get error logs on database startup without this.

Make sure to send a request only after the connection to the DB was established.

Related

Importing a specific function present in a file that contains a connection to the mongoose db crashes when running tests

I have a NodeJs app using express and MongoDB that I want to write unit tests for using Jest.
Here's the problem: I'm importing a specific function from the file reports.js. The function itself doesn't use the mongoose db, but I know that using require executes the entire file before returning the exported objects. That being said, when I'm running my test file, the "testing" part works fine, but I'm getting the reference error below since the importation is still in process when my tests are completed.
ReferenceError: You are trying to import a file after the Jest environment has been torn down. From tests/reportsLib.test.js.
I've done some research and a lot suggests to use jest.useFakeTimers() before running each tests. But the same error occurs. However, when I use jest.useFakeTimers() after importing mongoose in the payment.js file (which is not optimal since I would like to have everything about tests in the tests files), the error is fixed but another occurs on the following line: campaignstatsSchema.plugin(mongoose_delete, {deletedAt:true, overrideMethods: true})
TypeError: Invalid schema configuration: -ClockDate- is not a valid type at path -deletedAt-. See mongoose-schematypes for a list of valid schema types.
Another way to fix the 1st error is to import the function in a beforeAll() Jest function, but the 2nd error still occurs.
Is there some sort of refac needed for the way I'm connecting to my DB and creating my schemas/models? What's the best way to solve this issue? Thanks in advance!
reports.tests.js file:
const { functionToTest } = require('./../lib/reports');
describe('report.js testing', () => {
beforeEach(() => {
jest.useFakeTimers();
});
it('should return a value of 0', () => {
expect(functionToTest()).toBe(0);
});
});
reports.js file:
const db = require('./../services/db');
// ...other imports
const functionToTest = function() {
return 0;
};
const otherFunction = async function(report_id, report_data) {
//some code
await db.report.findOneAndUpdate({_id: report_id}, {data:report_data});
};
module.exports = {
functionToTest,
// other functions
};
db.js file:
const mongoose = require('mongoose');
const payment = require('../models/payment');
const report = require('../models/report');
mongoose.connection.setMaxListeners(0);
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true
});
const generateObjectId = function() {
return mongoose.Types.ObjectId();
};
const getTimestampFromId = function(id) {
return mongoose.Types.ObjectId(id).getTimestamp();
};
module.exports = {
report,
payment,
// other models
};
payment.js file:
const mongoose = require('mongoose');
const mongoose_delete = require('mongoose-delete');
const mongoose_history = require('mongoose-history');
const paymentProfileSchema = mongoose.Schema({
// fields here
});
paymentProfileSchema.plugin(mongoose_history);
paymentProfileSchema.plugin(mongoose_delete);
const paymentProfile = mongoose.model('payment-profiles', paymentProfileSchema);
paymentProfile.syncIndexes();
module.exports = paymentProfile;

MongoNotConnectedError: MongoClient must be connected to perform this operation. How to handle this error?

cmd
How can i solve this. Just showing MongoClient must be connected to perform this operation
at getTopology ..... at collection.insertOne .... at maybePromise..
const express = require('express');
const {MongoClient} = require('mongodb');
const password = 'NLJXkuGFhUd68#9';
const uri = "mongodb+srv://organicUser:NLJXkuGFhUd68#9#cluster0.px7rc.mongodb.net/organicdb?retryWrites=true&w=majority";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
const app = express();
app.get('/', (req, res) => {
res.send("Hello, I am Working");
})
client.connect(err => {
const collection = client.db("organicdb").collection("products");
// perform actions on the collection object
const product = {name: "Modhu", price: 120, quantity: 30};
collection.insertOne(product)
.then(result => {
console.log("One product added");
})
console.log("database connected");
});
app.listen(8000)
Just comment the code or remove client.close()
finally {
// await client.close();
}
I had the same issue and I have changed the method to be await and async, and I added await to the operation.
So the operation will be finished then the connection will be close
I needed to replace # with %40 in the database password
As I'm struggling with this, the author is referring to the idea that if your password contains certain characters, you must change them out for percent based codes: If the username or password includes the following characters:
: / ? # [ ] #
those characters must be converted using percent encoding.
https://www.mongodb.com/docs/manual/reference/connection-string/

Mongoose not resolving callback queries?

I have been working on this project for 2 years now, and I'm thinking this was caused by the recent update, but am wondering if there are any kind, intelligent, Mongoose/NoSQL DBA, souls out there who would do the awesome service of helping me either track-down, and/or resolve this issue.
So, as you can see below, this is a simple mongoose find query over express to MongoDB. This is rather evident, at a high-level, and for most devs, the interactions will be natural, as any Mongo, Express, Node Stack using Mongoose.
The is issue is that, when I send this query, disregarding environment (a production project), it does not resolve.
The "data" seems to get lost somewhere, and therefore, the query simply never resolves.
It's a simple setup, really a test endpoint, so help out, run it through, and send some feedback.
Greatly Appreciated!
Model.js
const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate');
const Schema = mongoose.Schema;
const TestSchema = new Schema({
data: {
type: String,
unique: false,
required: true
},
}, {
timestamps: true
});
TestSchema.plugin(mongoosePaginate);
module.exports = mongoose.model('Test', TestSchema);
Constructor.js
class Constructor {
constructor() {}
getAll() {
return TestSchema.find({}, function (err, tests) {})
}
}
module.exports = Constructor
db.js
let mongoose = require('mongoose')
// Connect to db
mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true, useUnifiedTopology: true }, err => {
if (err)
return console.log("Cannot connect to DB")
connectionCallback()
console.log("DB Connected")
});
let connectionCallback = () => {}
module.exports.onConnect = cb => {
connectionCallback = cb
}
App.js
const express = require('express');
const app = express();
const ip = require('ip');
let db = require('./db')
const router = express.Router();
const port = 8888;
const http = require('http').createServer(app);
let ipAddress = 'localhost'; // only works to the local host
try {
// will enable the server to be accessed from the network
ipAddress = ip.address();
} catch( err ){
console.err( err );
}
http.listen(port, ipAddress,
() => {
let message = [
`Server is running at ${ipAddress}:${port}`,
];
console.log( ...message )
});
db.onConnect(() => {
let Constructor = require("./pathTo/Constructor")
let construct = new Constructor()
app.use('/api', router.get('/test', function(req, res) {construct.getAll()}))
})
Your problem is with the constructor.js getAll function, as you are returning also and passed a callback also, the promise will never be resolved. You should either resolve the promise or return the response from the callback.
Resolve Promise:
class Constructor {
constructor() {}
async getAll() {
return await TestSchema.find({})
}
}
module.exports = Constructor
Return from callback:
class Constructor {
constructor() {}
getAll() {
TestSchema.find({}, function (err, tests){
return tests.
})
}
}
module.exports = Constructor
I ended up just scaling the project for production. I put the connectionCallback in a class and called it with the createConnection mongoose function.
Looks like this:
mongoose.Promise = global.Promise;
const url = 'mongodb://localhost/db'
const connection = mongoose.createConnection(url, options);
//load models
require('/models').connectionCallback();
modules.export = connectionInstance;
Please note, I am no longer using express!

Exporting mongoose connections to my model.js file

I just migrated from Mongoose 3 to 5.1.5 and have some issues. I have a nodejs application running trying to connect to multiple DBs on different hosts.
Connection.js file : This is used to maintain the connections.
I am exporting my connections to my models and binding the schemas
Connection.js file
const mongoose = require('mongoose');
const Mongoose = mongoose.Mongoose;
mongoose.Promise = require('bluebird');
-
-
const _connect = function (mongoUrl, options) {
mongoose.connect(mongoUrl, options).then(
() => { console.log('MongoDB Connected.'); },
err => { console.log('MongoDB not Connected.'); }
);
}
-
module.exports = {
conn1: new Connection('DB1'),
conn2: new Connection('DB2')
};
In model.js
I have created different models and each is saved as a different file.
const mongoose = require('mongoose');
const connections = require('./Connections');
-
-
const schema = new mongoose.Schema(model);
if (fileName.toLowerCase().includes('db2')) {
connections.conn2.model(fileName, schema);
} else {
connections.conn1.model(fileName, schema);
}
The whole setup was working properly in 3.x, but in 5.1.5, i get an issue
"connections.conn1.model is not a function"
To test the whole scenario, I commented one connection and gave my exports as below in Connection.js:
module.exports = {
mongoose: new Connection('DB1'),
};
and in model.js I just had
mongoose.model(fileName, schema);
which works perfectly. Please let me know what am I doing wrong.

Express validator ".isEmpty()" not working

When I try to run my application I get an error saying that text boxes that are not empty are empty.
app.js:
https://pastebin.com/5pbVG7kq
index.hbs:
https://pastebin.com/neVV4X78
EDIT:
With express-validator, you need to use the "notEmpty()" function instead of validator's module "isEmpty()", which is not referenced in the readme.md. I tried it out with an empty string and without sending the parametr and it works fine in both cases.
OLD REPLY:
I'm facing the same issue with express-validator. I submitted the issue to the github respository so we have to wait for them to address the problem.
As a workaround in the meantime, you can use the isEmpty() function of the validator package directly.
var validator = require('validator');
validator.isEmpty(string) //returns true or false
Also note that validator only accepts a string value and it doesn't coerce the variable passed to it as opposed to express-validator, so you will need to handle the case when the parameter obtained via req.body.param is not sent.
Here is the link to the reported issue: https://github.com/ctavan/express-validator/issues/336
Hope this helps.
2019 express-validator
6.2.0
Here is what I use for now and it works perfect
app.js
const express = require('express');
const {createPost} = require('../controllers/post');
// Import check only form express-validator
const {check} = require('express-validator');
const router = express.Router();
router.post('/post',[
// Title
check('title').not().isEmpty().withMessage('Title is required.'),
check('title').isLength({
min:4,
max:150
}).withMessage('Title must be between 4 to 150 characters.'),
check('body').not().isEmpty().withMessage('Body is required.'),
check('body').isLength({
min:4,
max:2000
}).withMessage('body must be between 4 to 2000 characters.')
],createPost)
** Folder '../controllers/post'**
post.js
// Import validation result only from expres-validator
const {validationResult } = require('express-validator');
// Post model file with custom implementation.
const Post = require('../models/post');
exports.createPost = (req, res) => {
// Grab your validation errors here before making any CREATE operation to your database.
const errors = validationResult(req);
if (!errors.isEmpty()) {
const firstError = errors.array().map(error => error.msg)[0];
return res.status(400).json({ error: firstError });
}
const post = new Post({
title: req.body.title,
body: req.body.body
});
// Now you can safely save your data after check passes.
post.save()
.then(result => {
res.status(200).json({
post: result
})
});
};

Resources