express middleware mongodb execution not working - javascript

Using express middleware fetching user information from mongodb on page request.
Try to set userInfo in request but I am not getting userinfo in request please check the below code and suggest me.
app.js
app.use(userManager.userManager);
userManager.js
"use strict";
var USERModel = require("./user_schema");
module.exports.userManager = function(req, res, next) {
var assoString = "US";
var options = {
limit: 1
};
USERModel.textSearch(assoString, options, function (err, output) {
if (err) {
console.error("USERModel.textSearch:" ,err);
}
else if (output && output.results && output.results.length > 0) {
req.userInfo = output.results[0].obj.userDetail;
}
else {
console.warn("Empty USERModel for ", assoString);
}
});
};
user_schema.js
"use strict";
var db = require('../lib/db_connect');
var textSearch = require("mongoose-text-search");
var userSchema = new db.Schema({
associatedwith : String,
userDetail: {
userId : {type: String},
cId : {type: String},
device : {type: String},
contentType : {type: String},
isCompression : {type: Boolean},
renderType : {type: String}
}
}
);
userSchema.plugin(textSearch);
var USERModel = module.exports = db.mongoose.model('users', userSchema);

You need or reply the http request (with res.send, res.json, res.end and family) or invoke the callback to pass the request to the next middleware or route handler:
app.use(function(req,res,next){
// Rest of the logic
res.send(200,'Everything went OK'); // The request is replied here
});
app.use(function(req,res,next){
// Rest of the logic
next(); // To the next middleware/route logic
});

Related

Node js & mongo API : Error: socket hang up

Im trying to make an API with node JS (express and jwt) with a mongodb.
I've make some routes (like to get markers for example), that's working fine.
BUT i've also make a route in order to post some markers. When I query it (that takes long time, and with Postman), and I've an error like :
"Could not get any response"
and in my console :
Error: socket hang up
My route controller :
const model = require('../models/markers');
module.exports = {
create: function(req, res, next) {
model.create({
param_1: req.body.param_1,
param_2: req.body.param_2,
param_3: req.body.param_3,
}, function (err, result) {
if (err)
next(err);
else
res.json({status: "success", message: "Marker added successfully", data: null});
});
},
getAll: function(req, res, next) {
let list = [];
model.find({}, function(err, items){
if (err){
next(err);
} else{
for (let item of items) {
list.push({
id: item._id,
param_1: item.param_1,
param_2 : item.param_2,
param_3: item.param_3
});
}
res.json({status:"success", message: "Markers list found", data:{markers: list}});
}
});
},
};
And for my route :
const express = require('express');
const router = express.Router();
const markerController = require('../controllers/markers');
router.get('/', markerController.getAll);
router.post('/', markerController.create);
module.exports = router;
My model :
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MarkerSchema = new Schema({
param_1: {
type: String,
required: true
},
param_2: {
type: String,
},
param_3: {
type: [{
type: String,
enum: ['0.5', '1', ',1.25', '1.5', '2', '3+']
}],
default: ['pending']
}
});
module.exports = mongoose.model('Marker', MarkerSchema);
My get router works fine but my post route don't.
You should check #Will Alexander comment, if it's a copy paste you have a typo in:
param_2: req.bodyparam_2,

MongooseJS object undefined inside callback function

I'm trying to write an endpoint for an API that will return all orders for a given user. My issue is that when I try to query the database using mongoose's findById function, the 'user' object is undefined in the callback function and I can't query the orders subdoc. To add to the confusion, I can get it to work if I don't use a callback function, but then I don't have proper error handling.
var mongoose = require('mongoose');
var router = express.Router();
var order_model = require('../models/order');
var user_model = require('../models/user');
router.get('/:userid/order/', function (req, res) {
// This works???
var u = user_model.findById(req.params.userid);
res.json(u.orders);
});
The following code throws the error "TypeError: Cannot read property 'orders' of undefined".
var mongoose = require('mongoose');
var router = express.Router();
var order_model = require('../models/order');
var user_model = require('../models/user');
router.get('/:userid/order/', function (req, res) {
// This throws an error.
user_model.findById(req.params.userid).then(function (err, user) {
if (err) {
res.send(err);
}
res.json(user.orders);
});
});
user.js
var mongoose = require('mongoose');
var ordersSchema = require('./order').schema;
var userSchema = new mongoose.Schema({
name: String,
email: String,
showroom: String,
orders: [ordersSchema]
});
module.exports = mongoose.model('User', userSchema);
order.js
var mongoose = require('mongoose');
var lineItemsSchema = require('./lineitem').schema;
var ordersSchema = new mongoose.Schema({
trackingNumber: Number,
lineItems: [lineItemsSchema]
});
module.exports = mongoose.model('Order', ordersSchema);
Any help / explanation of this behavior would be appreciated. Thanks!
The first parameter of the then callback is user, not err.
Either use a traditional callback:
user_model.findById(req.params.userid, function (err, user) {
if (err) {
res.send(err);
return; // Need to return here to not continue with non-error case
}
res.json(user.orders);
});
Or chain a call to catch on the promise to separately handle errors:
user_model.findById(req.params.userid).then(function (user) {
res.json(user.orders);
}).catch(function(err) {
res.send(err);
});
I usually query like this, it work perfect :
user_model.find(_id : req.params.userid)
.exec((err, user) => {
if(err){
//handle error
}
return res.status(200).json(user.orders);
})
});

Express.js Server with iOS Swift Request Timing Out

I am trying to make an HTTP POST request using an iOS Swift app to an Express.js server. In the post request, I send JSON data, creating the JSON object using a dict and SwiftyJSON. However, the request continues to time out. I think it has something to do with 'body-parser', which is what I am using to parse the HTTP body. Here is my swift code:
override func viewDidLoad() {
super.viewDidLoad()
var dict = ["name": "FirstChannel", "verified": 0, "private": 1, "handle": "firstChannel", "subscribers": 0] as [String : Any]
var jsonData = JSON(dict)
do {
let post:NSData = try jsonData.rawData() as NSData
var postLength: NSString = String(post.length) as NSString
var url = URL(string: "http://10.0.0.220:3000/channel/createChannel")!
var request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = post as Data
request.setValue(postLength as String, forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main, completionHandler: { (resposne, data, error) in
if(error != nil) {
print(error)
}
else {
print(data)
}
})
}
catch {
print(error.localizedDescription)
}
}
And here is the code I use in my express.js router:
var express = require('express');
var router = express.Router();
var http = require('http');
var url = require('url');
var util = require('util');
var bodyParser = require('body-parser')
var ObjectID = require('mongodb').ObjectID;
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({extended: true}));
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');
var channelSchema = mongoose.Schema({
name: String,
verified: String,
private: String,
channelID: String,
handle: String,
subscribers: String
});
var Channel = mongoose.model("Channel", channelSchema);
router.post('/createChannel', bodyParser, function(req, res, next) {
req.body = true;
if(!req.body) return res.sendStatus(400);
var objID = new ObjectID();
var newChannel = new Channel({
name: req.body["name"],
verified: req.body["verified"],
private: req.body["private"],
channelID: objID,
handle: req.body["handle"],
subscribers: (req.body["subscribers"])
});
newChannel.save(function(err, point){
if(err) console.log(err);
else res.end();
});
});
If anybody could help me out and help this POST request succeed, I would greatly appreciate it. Thanks!
It doesn't look like you're sending back an HTTP 200 on success of your route - you only handle an error. Add a res.end(); at the end of your route (probably in the callback from the DB call) and try again.

Node js url shortener is looping rather than redirecting

I am writing a url shortener service in Node JS using mongo to connect to mLab.
Right now the user can send a request to the service with a url to shorten, and it returns a shortened url. However, if the user then sends the shortened url as a request, the redirect does not happen. Rather, the service goes into a loop.
1) How do I see what exactly is getting grabbed from the db? (Knowing how to do this would help out in trouble-shooting)
2) And what may be the cause of the looping issue?
var express = require('express')
var app = express()
var path = require('path');
var port = process.env.PORT || 8080;
var crypto = require("crypto");
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({ // this schema is used for writing to the db
url : String,
key : String
});
var urlcntrctr = new Schema( // this schema is used for reading from the db
{ key: String, url : String, _id: String },
{ collection: 'urlcntrctr'}
);
const SchemaName = mongoose.model('SchemaName', urlcntrctr); // for reading from the db
app.get('/', (req, res, next) => res.sendFile(path.join(__dirname, '/index.html')) ) ;
app.set('port', (process.env.PORT || 5000));
app.get('/new/:url(*)', function(req, res) {
var shortenme = req.params[0];
var showme = req.params[0];
console.log("User's request: " +shortenme);
var amItrue = validateURL(shortenme);
if (amItrue){
connectmongoviamongoose();
var shortenmeObj = yncryptyyn(shortenme);
shortenme = shortenmeObj.key;
writeToDb(shortenmeObj); b
closetheconnection();
var contractedurl = 'http://firstappever-olddognewtrix123.c9users.io/' + shortenme;
var responseObject = ({"Original url: ": showme, "Contracted url: ": shortenme });
res.send(responseObject);
}
else{console.log("You need to enter a url, beginning with 'http' or 'https' and ending in '.com' or '.org' or whatever!");};
})
app.get('/:tag(*)', function(req, res) {
var targetnumber = req.params.tag;
sendforRedirect(req, res);
sendforRedirect(req, res);
})
function sendforRedirect(req, res){
var target = req.params.tag;
console.log("The value of target is " + target)
; var options = { server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
replset: { socketOptions: { keepAlive: 1, connectTimeoutMS : 30000 } } };
var mongodbUri = 'mongodb://<dbusername>:<dbuserpassword>#ds159988.mlab.com:59988/urlcntrctr';
mongoose.connect(mongodbUri, options);
mongoose.Promise = global.Promise;
var conn = mongoose.connection;
conn.on('error', console.error.bind(console, 'connection error:'));
conn.once('open', function() {
console.log("OK, you are connected for the redirect. ")
var query = {
key: {
$eq: target
}
}
SchemaName.find(query, function (err, doc) {
if(err){
console.log(err);
conn.close();
};
if(doc){
res.redirect(doc.url); // rather than redirecting, it is looping *****************
conn.close();
} else {
res.send("Sorry, we don't recognize that url");
conn.close();
}
});
});
}
function writeToDb(dataObject){
mongoose.model('Document', UserSchema);
var urlFromUser = mongoose.model('Document');
var urlfromuser = new urlFromUser();
urlfromuser.url = dataObject.url;
urlfromuser.key = dataObject.key;
urlfromuser.save();
};
function validateURL(textval) { //copied from http://stackoverflow.com/questions/1303872/trying-to-validate-url-using-javascript
var urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*#)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/;
return urlregex.test(textval);
}
function connectmongoviamongoose(){
var mongoose = require('mongoose');
var options = { server: { socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } },
replset: { socketOptions: { keepAlive: 300000, connectTimeoutMS : 30000 } } };
var mongodbUri = 'mongodb://<dbusername>:<dbuserpassword>#ds159988.mlab.com:59988/urlcntrctr';
mongoose.createConnection(mongodbUri, options);
var conn = mongoose.connection;
conn.on('error', console.error.bind(console, 'connection error:'));
conn.once('open', function() {
console.log("OK, you are connected. ")
});
}
function closetheconnection(){
var mongoose = require('mongoose');
mongoose.connection.close();
}
function yncryptyyn(incryptme){
var ulimit = 6;
var key = crypto.createHash('md5').update(incryptme).digest("base64");
key = key.slice(0,ulimit);
var obj = {
url: incryptme,
key: key
};
return obj;
}
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
Better than console.log statements, you can use the package node-inspector to actually set breakpointsnin your code via chrome devtools and step through the code Much more robust process.
I would note that it is not clear to me what kind of urls you are shortening (internal to your site or external), but at present it looks like you're calling the redirect function twice, which should cause an error unto itself, and second if you are redirecting to internal urls your routes are probably going to match a lot that you don't want them to.
Finally, your code is kind of a jumble right now, which will make debugging harder no matter what you do. Try and break it out into different files based on what they do and test bits independently as much as possible.
For question 1: just put in a console.log, for example like this:
if(doc){
console.log(doc);
res.redirect(doc.url);
....
Even better put the whole functionality of the look up of the url into an own function, so you can check the working of the lookup and the working of the redirect independently.

node.js & express - global modules & best practices for application structure

I'm building a node.js app that is a REST api using express and mongoose for my mongodb. I've got the CRUD endpoints all setup now, but I was just wondering two things.
How do I expand on this way of routes, specifically, how do I share modules between routes. I want each of my routes to go in a new file, but obviously only one database connection as you can see i've included mongoose at the top of people.js.
Do I have to write out the schema of the model 3 times in my people.js? The first schema defines the model, then I list all the vars out in the createPerson and updatePerson functions. This feels like how I made php/mysql CRUD back in the day lol. For the update function, I've tried writing a loop to loop through "p" to auto detect what fields to update, but to no avail. Any tips or suggestions would be great.
Also, I'd love any opinions on the app as a whole, being new to node, it's hard to know that the way you are doing something is the most efficient or "best" practice. Thanks!
app.js
// Node Modules
var express = require('express');
app = express();
app.port = 3000;
// Routes
var people = require('./routes/people');
/*
var locations = require('./routes/locations');
var menus = require('./routes/menus');
var products = require('./routes/products');
*/
// Node Configure
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
// Start the server on port 3000
app.listen(app.port);
/*********
ENDPOINTS
*********/
// People
app.get('/people', people.allPeople); // Return all people
app.post('/people', people.createPerson); // Create A Person
app.get('/people/:id', people.personById); // Return person by id
app.put('/people/:id', people.updatePerson); // Update a person by id
app.delete('/people/:id', people.deletePerson); // Delete a person by id
console.log('Server started on port ' + app.port);
people.js
//Database
var mongoose = require("mongoose");
mongoose.connect('mongodb://Shans-MacBook-Pro.local/lantern/');
// Schema
var Schema = mongoose.Schema;
var Person = new Schema({
first_name: String,
last_name: String,
address: {
unit: Number,
address: String,
zipcode: String,
city: String,
region: String,
country: String
},
image: String,
job_title: String,
created_at: { type: Date, default: Date.now },
active_until: { type: Date, default: null },
hourly_wage: Number,
store_id: Number, // Inheirit store info
employee_number: Number
});
var PersonModel = mongoose.model('Person', Person);
// Return all people
exports.allPeople = function(req, res){
return PersonModel.find(function (err, person) {
if (!err) {
return res.send(person);
} else {
return res.send(err);
}
});
}
// Create A Person
exports.createPerson = function(req, res){
var person = new PersonModel({
first_name: req.body.first_name,
last_name: req.body.last_name,
address: {
unit: req.body.address.unit,
address: req.body.address.address,
zipcode: req.body.address.zipcode,
city: req.body.address.city,
region: req.body.address.region,
country: req.body.address.country
},
image: req.body.image,
job_title: req.body.job_title,
hourly_wage: req.body.hourly_wage,
store_id: req.body.location,
employee_number: req.body.employee_number
});
person.save(function (err) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "Person was not created." });
}
});
return res.send(person);
}
// Return person by id
exports.personById = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "That person doesn't exist." });
}
});
}
// Delete a person by id
exports.deletePerson = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
return person.remove(function (err) {
if (!err) {
return res.send(person.id + " deleted");
} else {
console.log(err);
return res.send(404, { error: "Person was not deleted." });
}
});
});
}
// Update a person by id
exports.updatePerson = function(req, res){
return PersonModel.findById(req.params.id, function(err, p){
if(!p){
return res.send(err)
} else {
p.first_name = req.body.first_name;
p.last_name = req.body.last_name;
p.address.unit = req.body.address.unit;
p.address.address = req.body.address.address;
p.address.zipcode = req.body.address.zipcode;
p.address.city = req.body.address.city;
p.address.region = req.body.address.region;
p.address.country = req.body.address.country;
p.image = req.body.image;
p.job_title = req.body.job_title;
p.hourly_wage = req.body.hourly_wage;
p.store_id = req.body.location;
p.employee_number = req.body.employee_number;
p.save(function(err){
if(!err){
return res.send(p);
} else {
console.log(err);
return res.send(404, { error: "Person was not updated." });
}
});
}
});
}
I have taken another approach here. Not saying it is the best, but let me explain.
Each schema (and model) is in its own file (module)
Each group of routes for a particular REST resource are in their own file (module)
Each route module just requires the Mongoose model it needs (only 1)
The main file (application entry point) just requires all route modules to register them.
The Mongo connection is in the root file and is passed as parameter to whatever needs it.
I have two subfolders under my app root - routes and schemas.
The benefits of this approach are:
You only write the schema once.
You do not pollute your main app file with route registrations for 4-5 routes per REST resource (CRUD)
You only define the DB connection once
Here is how a particular schema file looks:
File: /schemas/theaterSchema.js
module.exports = function(db) {
return db.model('Theater', TheaterSchema());
}
function TheaterSchema () {
var Schema = require('mongoose').Schema;
return new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
address: { type: String, required: true },
latitude: { type: Number, required: false },
longitude: { type: Number, required: false },
phone: { type: String, required: false }
});
}
Here is how a collection of routes for a particular resource looks:
File: /routes/theaters.js
module.exports = function (app, options) {
var mongoose = options.mongoose;
var Schema = options.mongoose.Schema;
var db = options.db;
var TheaterModel = require('../schemas/theaterSchema')(db);
app.get('/api/theaters', function (req, res) {
var qSkip = req.query.skip;
var qTake = req.query.take;
var qSort = req.query.sort;
var qFilter = req.query.filter;
return TheaterModel.find().sort(qSort).skip(qSkip).limit(qTake)
.exec(function (err, theaters) {
// more code
});
});
app.post('/api/theaters', function (req, res) {
var theater;
theater.save(function (err) {
// more code
});
return res.send(theater);
});
app.get('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.put('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.delete('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
return theater.remove(function (err) {
// more code
});
});
});
};
And here is the root application file, which initialized the connection and registers all routes:
File: app.js
var application_root = __dirname,
express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
http = require('http');
var app = express();
var dbProduction = mongoose.createConnection('mongodb://here_insert_the_mongo_connection_string');
app.configure(function () {
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(application_root, "public")));
app.use('/images/tmb', express.static(path.join(application_root, "images/tmb")));
app.use('/images/plays', express.static(path.join(application_root, "images/plays")));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.get('/api', function (req, res) {
res.send('API is running');
});
var theatersApi = require('./routes/theaters')(app, { 'mongoose': mongoose, 'db': dbProduction });
// more code
app.listen(4242);
Hope this was helpful.
I found this StackOverflow post very helpful:
File Structure of Mongoose & NodeJS Project
The trick is to put your schema into models directory. Then, in any route, you can require('../models').whatever.
Also, I generally start the mongoose db connection in app.js, and only start the Express server once the connection is up:
mongoose.connect('mongodb://localhost/whateverdb')
mongoose.connection.on('error', function(err) {
console.log("Error while connecting to MongoDB: " + err);
process.exit();
});
mongoose.connection.on('connected', function(err) {
console.log('mongoose is now connected');
// start app here
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
});
I'd take a look at this project https://github.com/madhums/node-express-mongoose-demo . It is a great example on how to build a nodejs application in a standard way.

Categories

Resources