Retrieving data from mlab heroku - mongodb

I followed a tutorial to learn Express.js App that performs basic CRUD operations from MongoDB. All operations created locally works fine.
As a next step (not in the tutorial), I needed to integrate mLab provided by Heroku for MongoDB in order to push the app to Heroku.
Now, I need to make necessary changes on the mongoose connection since I am moving from a local database to mLab. I made necessary changes but now the app throws an error.
complaintController.js (class to get request and use the model)
Complaint = require('./complaintModel');
exports.index = function (req, res) {
Complaint.get(function (err, complaints) { //GET function
if (err) {
res.json({
status: "error",
message: err,
});
}
res.json({
status: 200,
message: "Complaints retrieved successfully",
data: complaints
});
});
};
complaintModel.js (local MongoDB this works fine)
var mongoose = require('mongoose');
var complaintSchema = mongoose.Schema({
name: {
type: String,
required: true
},
});
// Export Complaint model
var Complaint = module.exports = mongoose.model('complaint', complaintSchema);
module.exports.get = function (callback, limit) {
Complaint.find(callback).limit(limit);
}
complaintModel.js ( connecting to mLab throws error)
var mongoDB = "MongoDB URI";
var connection = mongoose.createConnection(mongoDB,
{
User: 'username',
Password: 'pass'
});
var Complaint;
connection.on('open', function() {
console.log('connection established!!!');
Complaint = module.exports = connection.model('master_complaint', complaintSchema);
module.exports.get = function (callback, limit) {
Complaint.find(callback).limit(limit);
}
});
Here I get the following error when I give a get request I understood there is an export issue of Complaint Module but any suggestion or idea will be helpful.
TypeError: Complaint.get is not a function
at exports.index (R:\Workings\PersWork\web\webpack-demo\controller\complaintController.js:6:15)
at Layer.handle [as handle_request] (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\layer.js:95:5)
at next (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\layer.js:95:5)
at R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:281:22
at Function.process_params (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:335:12)
at next (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:275:10)
at Function.handle (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:174:3)
at router (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:47:12)
at Layer.handle [as handle_request] (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:317:13)
at R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:284:7
at Function.process_params (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:335:12)
at next (R:\Workings\PersWork\web\webpack-demo\node_modules\express\lib\router\index.js:275:10)
at jsonParser (R:\Workings\PersWork\web\webpack-demo\node_modules\body-parser\lib\types\json.js:110:7)

From what I can see in the code. complaintController will be used by the express.js router, Am I correct?
I also see in the complaintModel.js is that the get function you've exported requires 2 parameters which are a filter & a limit. But in the Controller file you're not providing any of those arguments at all.
I haven't tested this myself yet but try changing your complaintModel.js to this
var mongoose = require("mongoose");
var complaintSchema = mongoose.Schema({
name: {
type: String,
required: true
}
});
var Complaint = mongoose.model("master_complaint", complaintSchema);
// Exports the get function
module.exports.get = function(filter, limit, callback) {
var mongoDB = "MongoDB URI";
var connection = mongoose.createConnection(mongoDB, {
User: "username",
Password: "pass"
});
connection.on("open", function() {
console.log("connection established!!!");
Complaint.find(filter)
.limit(limit)
.exec()
.then(results => {
callback(undefined, results)
})
.catch(err => {
console.log(err);
callback("ERROR: Can't query the collection", undefined)
});
});
};
And change the complaintController.js to the following
var Complaint = require("./complaintModel");
module.exports.index = function(req, res) {
var params = req.query;
const filter = params.filter;
const limit = params.limit;
Complaint.get(
filter,
limit,
(err,
complaints => {
if (err) {
res.json({
status: "error",
message: err
});
} else {
res.json({
status: 200,
message: "Complaints retrieved successfully",
data: complaints
});
}
})
);
};

Related

Express Sequelize Error - Cannot read property 'findAll' of undefined

I have successfully connected Sequelize and Express using Sequelize's github example with a few changes. I am now trying to do a simple Sequelize query to test the connection, but continue to receive an error stating that the model I have queried is not defined.
// ./models/index.js
...
const sequelize = new Sequelize(process.env.DB, process.env.DB_USER, process.env.DB_PASS, {
host: 'localhost',
dialect: 'postgres'
});
// Test SEQUELIZE connection
sequelize
.authenticate()
.then(() => {
console.log('Database connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
var model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
// ./routes/index.js
const models = require('../models');
const express = require('express');
const router = express.Router();
router.get('/contacts', (req, res) => {
models.Contact.findAll().then(contacts => {
console.log("All users:", JSON.stringify(contacts, null, 4));
});
});
module.exports = router;
// ./models/contact.js
const Sequelize = require('sequelize');
var Model = Sequelize.Model;
module.exports = (sequelize, DataTypes) => {
class Contact extends Model {}
Contact.init({
// attributes
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING,
allowNull: false
}
}, {
sequelize,
modelName: 'contact'
// options
});
return Contact;
};
The error I am getting when using postman to hit /contacts with a GET request is:
[nodemon] starting `node server.js`
The server is now running on port 3000!
Executing (default): SELECT 1+1 AS result
Database connection has been established successfully.
TypeError: Cannot read property 'findAll' of undefined
at router.get (C:\Users\username\desktop\metropolis\metropolis-backend\routes\index.js:6:20)
You are not requiring the model properly.
In ./routes/index.js add the next line:
const Contact = require('./models/contact.js');
And then call Contact.findAll()...
Second approach:
You can gather all your models by importing them into a loader.js file which you will store in the models directory. The whole job of this module is to import the modules together to the same place and then export them from a single place.
It will look something like that:
// loader.js
const modelA = require('./modelA');
const modelB = require('./modelB');
const modelC = require('./modelC');
...
module.exports = {
modelA,
modelB,
modelC,
...
}
And then you can require it in the following way:
in router/index.js:
const Models = require('./models');
const contact = Models.Contact;

Error constructing as per schema

I have the following defined in my server.js,
//server.js
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var userSchema = new Schema({
"userName": {
type: String,
unique: true
},
"password": String,
"loginHistory": [{
"userAgent": String,
"dateTime": Date
}]
});
var User;
module.exports.initialize = () => {
return new Promise(function (resolve, reject) {
let db = mongoose.createConnection("mongodb://<dbuser>:<dbpassword>#ds237409.mlab.com:37409/web322_a6");
db.on('error', (err)=>{
reject(err); // reject the promise with the provided error
});
db.once('open', () => {
User = db.model("users", userSchema);
resolve();
});
})
};
I have a function that is called when posting to my app.post('/register') route, and it basically builds a new User, then assigns it to the passed data, and resolves it afterwards.
module.exports.registerUser = (userData) => {
return new Promise((resolve, reject) => {
if (userData.password != userData.password2) {
reject("Passwords do not match!");
}
let newUser = new User(userData);//<!-- 'Error: TypeError: User is not a constructor'
newUser.save((err) => {
if(err.code == 11000) {
reject("Username already taken");
} else {
reject("Error creating User: " + err);
}
// exit the program after saving
//process.exit();
resolve();
});
})
}
At first I thought I've misdefined User, but I seem to have initialized it properly, as per the MongoDB documentation. Any thoughts? It keeps throwing Error: TypeError: User is not a constructor
EDIT: /post / register
app.post("/register", (req, res) => {
console.log("entering1");
dataServiceAuth.registerUser(req.body).then((data) => {
res.render('register', {successMessage: "User Created"});
}).catch((err) => {
console.log("Error: " + err);
res.render('register', {errorMessage: err, userName: req.body.userName});
})
});
My error was in,
let db = mongoose.createConnection("mongodb://<dbuser>:<dbpassword>#ds237409.mlab.com:37409/web322_a6");
The greater than and less than signs are not to be used. Proper string:
let db = mongoose.createConnection("mongodb://dbuser:dbpassword#ds237409.mlab.com:37409/web322_a6");

MongoDB document not saved but showing success

I have a problem. I'm trying to save answers from a survey. My problem is that I'm sending these answers through axios and they are showing in the console.log from the server, which means that my data is reaching the server safely. But data is not being saved. Also no error is shown.
Server.js
router.route('/answers')
//post answers to database
.put(function(req, res){
var survey = new Survey();
survey.name = req.body.name;
survey.email = req.body.email;
survey.q_id = req.body.q_id;
survey.q_text = req.body.q_text;
survey.answer = req.body.answer;
console.log(Survey.collection)
survey.save(function(err){
if(err){
console.log(err)
return ;
}
res.send(survey);
});
})
Survey.js (Model)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = mongoose.Schema.Types.ObjectId;
var question = new Schema({
q_text:String,
order: Number,
options:[{
type: {type: String},
value: {type: String}
}]
});
module.exports = mongoose.model('Question',question);
Code that is posting the data
const url = 'http://localhost:3100/api/answers';
axios.put(url, survey)
.then(res => {
console.log('Successfully posted');
console.log(res);
setSubmitting(false);
setStatus({submitted: true});
})
.catch(err => {
console.log(err);
})
Try this :
survey.save(function(err, savedSurvey){
if(err){
console.log(err)
return ;
}
res.send(savedSurvey);
});

Can't set headers after they are sent. Error when Creating a sub-document with Mongo

I am trying to create a sub-document with my express API through postman with the following request:
POST /api/course/58c6f76e06e6edda1b000007/subject/58c6f85280a5d6591c000007/question
I am also sending x-www-forum-urlencoded data with names question and answer.
Here is the error that is output in the terminal:
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/home/tyler/Dropbox/Projects/Curricula/node_modules/express/lib/response.js:719:10)
at ServerResponse.send (/home/tyler/Dropbox/Projects/Curricula/node_modules/express/lib/response.js:164:12)
at ServerResponse.json (/home/tyler/Dropbox/Projects/Curricula/node_modules/express/lib/response.js:250:15)
at sendJSONResponse (/home/tyler/Dropbox/Projects/Curricula/API/controllers/question.js:8:8)
at Promise.<anonymous> (/home/tyler/Dropbox/Projects/Curricula/API/controllers/question.js:36:10)
at Promise.<anonymous> (/home/tyler/Dropbox/Projects/Curricula/node_modules/mpromise/lib/promise.js:171:8)
at emitOne (events.js:77:13)
at Promise.emit (events.js:169:7)
at Promise.emit (/home/tyler/Dropbox/Projects/Curricula/node_modules/mpromise/lib/promise.js:88:38)
Here is my controller file and relevant data models:
var mongoose = require('mongoose');
var Course = mongoose.model('Course');
var Subject = mongoose.model('Subject');
var Question = mongoose.model('Question');
var sendJSONResponse = function(res, status, content){
res.status(status);
res.json({content});
};
var addQuestion = function(req, res, subject){
if(!subject){
sendJSONResponse(res, 404, {"message":"subjectid not found"});
return;
}
else{
subject.questions.push({question: req.body.question,
answer: req.body.answer,
falseAnswer: req.body.falseanswer});
subject.save(function(err, course){
var thisQuestion
if(err){
sendJSONResponse(res, 400, err);
} else{
thisQuestion = subject.questions[subject.questions.length - 1];
sendJSONResponse(res, 201, thisQuestion);
}
});
}
}
var seekSubject = function(req, res, course){
if(req.params && req.params.subjectid){
Subject.findById(req.params.subjectid).exec(function(err, subject){
if(!subject){
sendJSONResponse(res, 404, {"message":"subjectid not found"});
}
else if(err){
sendJSONResponse(res, 404, err);
return;
}
sendJSONResponse(res, 200, subject);
return subject
});
} else{
sendJSONResponse(res, 404, {
"message":"no subjectid in request"
});
}
};
module.exports.makeQuestion = function(req, res){
var courseid = req.params.courseid;
if(courseid) Course.findById(courseid).select('subjects').exec(
function(err, course){
if(err){
sendJSONResponse(res, 400, err);
return;
}
else var subject = seekSubject(req, res, course);
addQuestion(req, res, subject);
});
}
Course Model
var mongoose = require('mongoose')
var subject = require('./subject.js');
var courseSchema = new mongoose.Schema({
name : {type: String,
unique: true,
required: true},
subjects : [subject.schema]
});
Subject Model
module.exports = mongoose.model('Course', courseSchema);
var mongoose = require('mongoose')
var question = require('./question.js');
var subjectSchema = new mongoose.Schema({
name : String,
questions : [question.schema]
});
module.exports = mongoose.model('Subject', subjectSchema);
Question model
var mongoose = require('mongoose')
var questionSchema = new mongoose.Schema({
question: {type: String, required: true},
answer: {type: String, required: true},
falseAnswer: [String]
});
module.exports = mongoose.model('Question', questionSchema);
What am I doing wrong in creating the entry?
It could be in this area
else var subject = seekSubject(req, res, course);
addQuestion(req, res, subject);
those 2 function, seekSubject and addQuestion seem like that are both calling sendJSONResponse and they both seem like that they sending a response
res.status(status); res.json({content});
So if both functions are being called in that area you are likely sending 2 responses and that is why you are getting that error.
You are doing good by separating the concerns but you got to get the error stuff separate too. your telling the server to respond twice when you call the 2 function. I think your calling both functions. I haven't ran your code.
You get this because you are sending 2 responses when you should send just 1. Try doing the following:
res.status(500).json({ error: 'message' });
Or you might want to try using return before sendJSONResponse(res, status, content); like so for example:
return sendJSONResponse(res, 404, {"message":"subjectid not found"});
Hope this helps you out.

remove value from mongoDB array

hi i am trying to remove a value from mongoDB but instead of removing a specific value the code is deleting all users from the schema lol.
var mongoose = require('mongoose');
var User = require('../../models/UserModel');
module.exports.unfollow = function(req, res){
var thefollowee = req.body.followee;
var thefollower = req.body.follower;
User.find({_id: thefollower}).remove({following: thefollowee}).exec();
User.find({_id: thefollowee}).remove({followers: thefollower}).exec();
res.json({ message: 'Unfollowed'});
};
the followee is pointing to the id of the person being followed,
the follower is pointing to the id of the user who follows the followee.
ok so i got it by using the $pull method
var mongoose = require('mongoose');
var User = require('../../models/UserModel');
module.exports.unfollow = function(req, res){
var thefollowee = req.body.followee;
var thefollower = req.body.follower;
User.findByIdAndUpdate(thefollowee, { $pull: { followers: req.body.follower }}, function (err, user) {
if (err)
return handleError(err);
});
User.findByIdAndUpdate(thefollower, { $pull: { following: req.body.followee }}, function (err, user) {
if (err)
return handleError(err);
});
res.json({ message: 'Unfollowed'});
};