I went through this express tutorial. I was wondering if it is possible to outsource the following call to a separate function, as it is very very long?
employee_collection.db.bson_serializer.ObjectID.createFromHexString(id)
This is the whole file where the statement is called:
var Db = require('mongodb').Db;
var Connection = require('mongodb').Connection;
var Server = require('mongodb').Server;
var BSON = require('mongodb').BSON;
var ObjectID = require('mongodb').ObjectID;
EmployeeProvider = function(host, port) {
this.db = new Db(
'node-mongo-employee',
new Server(host, port, {}),
{safe: true}
);
this.db.open(function(){});
};
...
// find an employee by id
EmployeeProvider.prototype.findById = function(id, callback) {
this.getCollection(
function(error, employee_collection) {
if( error )
callback(error)
else {
employee_collection.findOne(
{_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(id)},
function(error, result) {
if( error )
callback(error)
else
callback(null, result)
}
);
}
}
);
};
...
exports.EmployeeProvider = EmployeeProvider;
It's the controller of an express application. It's shortened, but should give you an idea of what it does. You can find the whole application on Github.
I tried
getid = function( employee_collection, id ) {
return employee_collection.db.bson_serializer.ObjectID.createFromHexString(id);
};
and called the function with
{_id: getid(employee_collection, id),
but I'm getting a very long ENOENT error with that one.
Presuming that you are working with the basic node.js mongodb driver here and that you have id essentially coming in as something like a request parameter, which means it's just a string and looks something like:
"53cfba87e248860d16e1f7e1"
Then the import you have used here:
var ObjectID = require('mongodb').ObjectID;
Gives you a direct function to use. Just do this:
employee_collection.findOne({ "_id": ObejctID(id) },function(err,result) {
// work in here
});
The ObjectID you are importing already implements this function.
Related
I have 2 collections setup as below, Dates and Streets.
What I would like to achieve is to, query Streets by a param StreetName and look that up to find it's unique ID and then query the other collection by that ID to pull back all the dates that match.
My route is set up to /wasteDate/:StreetName. Here's what I have:
model.js
var DateSchema = new Schema({
date: {
type: Date
},
street_id: {
type: String,
}
});
var StreetSchema = new Schema({
name: {
type: String
}
});
routes.js
module.exports = function(app) {
var wasteCollections = require('../controllers/wasteController');
app.route('/wasteDate/:streetName')
.get(wasteCollections.get_dates_by_street_name);
};
controller.js
var mongoose = require('mongoose'),
ColDate = mongoose.model('Dates'),
that = this,
Street = mongoose.model('Streets');
(...)
exports.manual_get_dates_by_street = function (id) {
var wasteDates = ColDate.find({ street_id: id }).lean();
return wasteDates;
};
exports.get_dates_by_street_name = function (req, res) {
Street.find({
name: req.params.streetName
}, function(err, street) {
var query;
var theStreetId = street[0].id;
if (err) res.send(err);
query = that.manual_get_dates_by_street(theStreetId);
res.json(query);
});
};
at the moment i'm getting a circular reference error on the JSON.
I don't think I'm doing it the right way and think I may need to amend my schema?
Any help appreciated
You can either use (1) find twice or (2) aggregation.
Here's the first way:
exports.manual_get_dates_by_street = function (id, callback) {
// you are dealing with asynchronous operations, so you have to wait for the callback
// to execute before you can get the data
ColDate.find({ street_id: id }).lean().exec(callback);
};
exports.get_dates_by_street_name = function (req, res) {
// you are expecting one result, so use findOne instead of find
Street.findOne({ name: req.params.streetName }, function (err, street) {
// make sure you handle errors properly such as stopping execution of
// the next lines or else you may get unexpected errors
if (err)
return res.send(err);
// we pass a callback that will be executed once results (or an error) are found
that.manual_get_dates_by_street(street._id, function (err, dates) {
res.json({ dates: dates });
});
});
};
I never used it but I think mongoose-models may resolve your problem. https://github.com/SportZing/mongoose-models
Another possible approach is to put the second query function as a callback of the first.
I've set up a node.js server-app that I want to do some parse.com requests.
I basically want it to return the parse-object JSON-representation.
My route:
var blog = require('./models/model');
app.get('/api/article/:permalink', function(req, res) {
res.json(blog.getArticle(req.params.permalink));
});
And my model:
var Parse = require('parse/node').Parse, // load the parse for node package
keys = require('../../config/keys'); // keys config-file for hosted services
Parse.initialize(keys.app, keys.js);
module.exports = {
getArticle: function(permalink) {
"use strict";
var Article = Parse.Object.extend('Article');
var query = new Parse.Query(Article);
query.include('category');
query.include('profile');
query.equalTo('permalink', permalink);
query.find().then(function(results) {
return results;
}, function(error) {
return error;
});
}
};
The thing is, this returns nothing when I call an article with a permalink that I know to exist (example: http://localhost/api/article/testFoo). I don't get any errors either.
My browser console flashes a message for a split second that reads:
Resource interpreted as Document but transferred with MIME type application/json: "http://localhost/api/article/testFoo"
Any suggestions to what I am doing wrong?
You are trying to use the return value of an async function. This can't work, you need to pass a callback (or the res object) to your getArticle function, which will then use it to send the data back.
With a callback:
app.get('/api/article/:permalink', function(req, res) {
blog.getArticle(req.params.permalink, function(data) {res.json(data)});
});
...
getArticle: function(permalink,callback) {
...
query.find().then(function(results) {
callback(results);
}, function(error) {
callback({error: error});
});
I'm using Express and trying to teach myself node/javascript callbacks and I've stumbled across something.
I have a route that looks like this:
var express = require('express');
var router = express.Router();
var api = require('../api');
router.get('/',function(req, res, next){
var modulename = api.modulename;
modulename.methodname(res);
});
module.exports = router;
And then the module that is being called above looks like this:
var library = require('library');
var instances = {};
var modulename = {
getAllInstances: function(res) {
var request = new library.asyncMethod();
request.on('success', function(resp) {
instances = resp.data;
res.setHeader("Content-Type","application/json");
var returnInstances = {
id: instances[0].InstanceId,
state: {name: instances[0].State.Name, code: instances[0].State.Code}
};
res.send(returnInstances);
})
.on('error', function(resp){
console.log(resp);
})
}
};
module.exports = modulename;
As you can see I'm passing through the response parameter through to my module, but I'd rather pass back instances and then in the route return api.modulename.instances, like this:
var library = require('library');
var instances = {};
var modulename = {
getAllInstances: function() {
var request = new library.asyncMethod();
request.on('success', function(resp) {
var returnData = resp.data;
instances = {
id: returnData[0].InstanceId,
state: {name: returnData[0].State.Name, code: returnData[0].State.Code}
};
})
.on('error', function(resp){
console.log(resp);
})
.send();
}
};
module.exports = modulename;
However, when I do, it's coming through as the default value {} but if I run it as above, I do get output so I know that there should be data in there.
Let me know if I have misunderstood your issue. If you are saying you want to pass back objects from getAllInstances then you pass in a callback and call it from the event handler like this-
router.get('/',function(req, res, next){
var modulename = api.modulename;
modulename.getAllInstances(res, function(err, instances){
if(err){ ... }
else{
res.send(instances); //or however you want to use instances
}
});
});
and in getInstances
var modulename = {
getAllInstances: function(res, cb) {
var request = new library.asyncMethod();
request.on('success', function(resp) {
instances = resp.data;
var returnInstances = {
id: instances[0].InstanceId,
state: {name: instances[0].State.Name, code: instances[0].State.Code}
};
cb(null, instances);
})
.on('error', function(err){
cb(err, null));
});
//.send(); not sure what this is it seems to be request.send() ??
}
};
The problem here lies with when the response from the API call is available. The event loop in Node means code won't block until the API replies with a response. Hence a callback is needed to handle that response when it becomes available. You probably want to use the API response in your Express router response so there's a chain of dependency.
One strategy here would be to use promises and not callbacks, it would alleviate some of the pain you're experiencing with async response from the API call.
In your routes:
router.get('/',function(req, res, next){
var instances = [];
// The function below could be refactored into a library to minimise controller code.
var resolver = function (response) {
var data = JSON.parse(response);
instances.push({
name: data[0].State.Name,
code: data[0].State.Code
});
res.render('instances'. {instances : instances});
};
modulename.methodname(resolver);
});
And in your module:
var rp = require('request-promise'); // Also see q-io/http as an alternate lib.
var modulename = {
methodname: function (resolver) {
rp('http://the-inter.net')
.then(resolver)
.catch(console.error);
}
};
This might not cut-n-paste work but have a look at the request-promise examples for further clarification.
I need to develop a module for getting data from mongodb, I already have other models working in my application, but this one does not, this is my schemas:
var mongoose = require('mongoose');
var ProvinciaSchema = new mongoose.Schema({
"nome":String,
"tc_provincia_id":Number,
"id" : Number,
"codice_regione" : Number,
"codice" : Number,
"sigla" : Number
},{collection:'province'})
module.exports = ProvinciaSchema;
this is my model:
var mongoose = require('mongoose');
var ProvinciaSchema = require('../schemas/provincia');
var Provincia = mongoose.model('provincia', ProvinciaSchema);
module.exports = Provincia;
This is how I use the model:
var Provincia = require('../../models/provincia');
Provincia.find({},next( err, province){
if (err){console.log('errorre whoosh '+err);
return next(err,province)
}
if (!province){console.log('trovato nulla')}
console.log('callback tc_istat_id')
return next(err,province)
})
where
next =function(err,prov){
t.equivalent(out,expect)
t.end()
when I launch the test if the condition argument is correct, the execution stuck at Provincia.find and the callback function it is not executed, if I put a wrong condition the section of the code of if(err) is executed, I think there is a problem with my schemas abnd models, but I do not understand what.
function myFunction(callback) {
Provincia.find({},next( err, province){
if (err) {
console.log('errorre whoosh '+err);
return next(err,province)
}
if (!province){
console.log('trovato nulla');
return false;
}
console.log('callback tc_istat_id')
callback(err,province)
})
}
myFunction(function(err,prov){
t.equivalent(out,expect)
t.end()
});
I had no way of testing this but it is how I would set up my callback function. Let me know what you log, and what errors your get if this does not work
http://senchalabs.github.com/connect/middleware-session.html mentions....
"Every session store must implement the following methods: "
.get(sid,callback)
.set(sid, session, callback)
.destroy(sid, callback)
I'm using the following code to attempt to get the SID:
Node JavaScript, using Socket.io connection
io.sockets.on('connection', function(socket) {
var sid = socket.id;
if (sid) {
sessionStore.get(sid, function (error, session) {
console.log("Connect Sid: " + sid);
});
}
});
And i'm getting the following error:
TypeError: Object function RedisStore(options) {
options = options || {};
Store.call(this, options);
this.client = new redis.createClient(options.port || options.socket, options.host, options);
if (options.pass) {
this.client.auth(options.pass, function(err){
if (err) throw err;
});
}
if (options.db) {
var self = this;
self.client.select(options.db);
self.client.on("connect", function() {
self.client.send_anyways = true;
self.client.select(options.db);
self.client.send_anyways = false;
});
}
} has no method 'get'
Inclusion of redis
//Redis store for storage
var sessionStore = require('connect-redis')(express);
...
...
app.use(express.session({secret: "keyboard cat",store: new sessionStore}));
Looks like you forgot to type new when you instantiated the store perhaps?
Taken from: https://github.com/visionmedia/connect-redis
This means express users may do the following, since express.session.Store points to the connect.session.Store function:
This seems to work:
express.session.Store(sid, function(){ console.log("Connect Sid: " + sid); });
I do it like this:
var RedisStore = require('connect-redis')(express);
var sessionStore = new RedisStore;
...
app.use(express.session({secret: "keyboard cat",store: sessionStore}));
This way you can reference session data using the sessionStore object from socket.io code later if needed.