Why does this
router.get('/eventTest/:id', function (req, res) {
var event = Event.getEventById(req.params.id, function (err, rows) {
if(err) {
return err;
} else {
return rows;
}
});
res.json(event);
});
returns
{
"domain": null,
"_events": {},
"_eventsCount": 0,
"_callSite": {},
"_ended": false,
"_idleNext": null,
"_idlePrev": null,
"_idleStart": null,
"_idleTimeout": -1,
"_repeat": null,
"sql": "select * from event where id=?",
"values": [
"1"
],
"typeCast": true,
"nestTables": false,
"_resultSet": null,
"_results": [],
"_fields": [],
"_index": 0,
"_loadError": null
}
this and example of one of the methods that I'm calling
`getEventById:function(id,callback){
return db.query("select * from event where id=?",[id],callback);
}
`
rather than the actual values like it does when I use res.json(rows) inside the Event.getEventById callback?
I need this in order to call multiple methods and add them to an object and then send that object in JSON
Thank you
As per your code, yes you need to send response from method.
Since as Node.js nature is async so you need to write your code in that way
Try it in your route
Event.getEventById(req.params.id, function (err, rows) {
if(err) {
res.status(500).send(err);
} else {
res.status(200).send(rows);
}
});
UPDATE
To execute multiple methods and send all records at single time then go through
async module or promise
I tried "express-promise" like this:
`router.get('/eventTest/:id', function (req, res) {
res.json({
details: Event.getEventById(req.params.id),
stages: Event.getEventStages(req.params.id)
});
});`
and still got the same result (i.e. the query and not the values). I'm guessing that my problem is the way that I managing the callbacks from the methods. Is this right?
router.get('/eventTest/:id', function (req, res, next) {
Event.getEventById(req.params.id, function (err, rows) {
if(err)
return next(err);
res.json(rows);
});
});
Related
I need to get the value of "data":3 from API1 and check in API2 if the field "data" has value greater than or equal to 3. I need to create a new API with API2 fields alone passing the filter criteria, please check the desired Json:
Json :
[
{
"fieldid": "0001",
"data": 3 , ---- API 1
"field7": "2018-12-06T11:49:52.389Z"
},
[
{
"field1": "E004",
"data": 3, --- api 2
"field7": "2018-12-06T11:49:52.389Z"
},
{
"field1": "E005",
"data": 2, ---- api 2
"field7": "2018-12-06T11:49:52.389Z"
}
],
]
Function :
n getlistofStaffs(req, callback) {
log.info(path.basename(module.filename), "List Staffs :: getlistofStaffs()");
var listofStaffsAPI = api url;
const requestOptions = {
url: listofStaffsAPI,
json: true
};
request(requestOptions, function (err, res, body) {
if (err) {
return callback(true, null);
} else if (res.statusCode == 200) {
var clearancesstaff=body[0].clearanceLevel;
var staffClearanceId = body[0].staffClearanceId;
return callback(null, {staffClearanceId:body[0].staffClearanceId,clearancesstaff:body[0].clearanceLevel});
}
});
}
Desired Output JSON :
[ {
"fieldid": "0001",
"data": 3 ,
"field7": "2018-12-06T11:49:52.389Z"
}
]
Thanks
Since you're using the async library, you'll want to make use of the .waterfall() method, which passes the callback data from one callback to the input of the next function. Since I'm not entirely sure what your existing functions do, I'll demonstrate the signature I think is necessary to what you're trying to do, but leave the details up to you.
function getListofStaffs(req, callback) {}
function getListofEvents(req, fieldname, callback) {}
// later
module.exports = (req, res, next) => {
async.waterfall([
getListofStaffs.bind(null, req),
getListofEvents.bind(null, req)
], (err, results) => {
if (err) return next(err);
return res.send(results);
});
}
If you're able to do it, it may be slightly more easy to follow your code if you're able to use the async/await features available in the last few versions of node. If you can, then you'll just make sure your API calls return Promises, and then you can do this:
async function getListofStaffs(req) {}
async function getListofEvents(req, fieldname) {}
module.exports = async (req, res, next) => {
try {
const fieldname = await getListofStaffs(req);
const events = await getListofEvents(req, fieldname);
res.send({ fieldname, events });
} catch (err) {
return next(err);
}
}
There's also the asynchandler module you can use if you don't want try..catch blocks in your routes.
EDIT
As mentioned in my comment, you need to update your getListofEvents function to expect three parameters, based on your current design:
function getlistofEvents(req, clearanceData, callback) {
var dt = dateTime.create();
var formatted = dt.format('Y-m-d');
console.log(formatted);
console.log(clearanceData);
log.info(path.basename(module.filename), "List Events :: getlistofEvents()");
var listofEventsAPI = www.gmail.com;
const requestOptions = {
url: listofEventsAPI,
json: true
};
request(requestOptions, function (err, res, result) {
if (err) {
return callback(true, null);
} else if (res.statusCode == 200) {
return callback(null, result);
}
});
}
Of course, your example code doesn't actually use that data, so I added a console.log to show it's there.
I'm trying to setup (this is my first attempt) a function that receives input, passes it through a function, then the results of that through a follow up.
I'm getting the following error
TypeError: Cannot read property 'exec' of undefined
I've never used Promises before and I believe that's what I should be doing in this instance, I don't think I'm quite understanding how to structure things with the .exec and .then parts.
app.get('/api/gameobjects/:userid/:golng/:golat/:dist', (req, res) =>
{
console.log("First part");
GameObject.getNearGameObjects(req.params.golng, req.params.golat, req.params.dist)
.exec((err, gameobject) =>
{
if (err)
{
res.json(err);
}
})
.then((gameobject) =>
{
console.log("Third part");
User.addGameObjectToUser(req.params.userid, gameobject)
})
});
EDIT:
Code for the getNearGameObjects:
// Get Near Game Objects
module.exports.getNearGameObjects = function( long, lat, dist, callback, limit )
{
var coords = [];
coords[ 0 ] = long;
coords[ 1 ] = lat;
var query =
{ geometry: { $near: { "$geometry": { "type": "Point", "coordinates": [long, lat] }, $maxDistance: dist } } };
GameObject.find( query, callback ).limit( limit );
};
Code for the addGameObjectToUser
// Add object to user
module.exports.addGameObjectToUser = function(id, gameobject, callback)
{
var query = { _id: id };
User.findByIdAndUpdate( query, { "$addToSet" : { "inventory" : gameobject } } );
};
If you don't return anything from the function, by default it returns undefined
You're getting
TypeError: Cannot read property 'exec' of undefined
because .exec() will be called on the returned undefined.
If you want to call .exec() on the find(), you should remove callback parameter on it. So that it returns promise
Making those changes,
module.exports.getNearGameObjects = function (long, lat, dist, callback, limit) {
return GameObject.find({
geometry: {
$near: {
"$geometry": {
"type": "Point",
"coordinates": [long, lat]
},
$maxDistance: dist
}
}
}).limit(limit);
};
Similarly, .catch() will handle error when it occurs.
GameObject.getNearGameObjects(req.params.golng, req.params.golat, req.params.dist)
.exec().then((gameobject) => {
console.log('Third part');
return User.addGameObjectToUser(req.params.userid, gameobject);
}).catch((err) => {
res.json(err);
});
I decided to go back to the code I know and nested by called based on result, this means more code, but more importantly it works.
I'd still be very interested in understanding how to do promise based code in the API, as it does look like it would be a tidier format to work with.
Here's the working code:
app.get('/api/gameobjects/:userid/:golng/:golat/:dist', function (req, res)
{
console.log("starting");
GameObject.getNearGameObject(req.params.golng, req.params.golat, req.params.dist, function (err, gameobject)
{
if (err)
{
res.json(err);
}
console.log("got a game object");
User.addGameObjectToUser(req.params.userid, gameobject, function (err, user)
{
if (err)
{
res.json(err);
}
console.log("updated a user");
GameObject.removeGameObjectByLocation(req.params.golng, req.params.golat, function(err, gameobject)
{
if (err)
{
res.json(err);
}
console.log("removed a game object");
res.json(gameobject);
});
});
});
});
I am using the async.map function to call a neo4j database on each element of "arrayOne".
async.map(
arrayOne,
function(item, callback){
getClientsNb({id:item},function (err, res) {
if (err) {console.log(err); return callback(err);}
console.log(res.results[0].data); //1
callback(null,res.results[0].data);
});
},
function(err,res) {
if (err) return console.log(err);
console.log(res); //2
}
)
The first console.log displays what I want:
[ { row: [ 'DIE ZAUBERFLOETE-2013', 1355 ] } ]
But the second console.log in the final function does not display the same result:
[ { row: [Object] } ],
Where does it come from? I would like to have the same result in the second console.log.
NB: the getClientsNb function is the following:
function getClientsNb(param, callback) {
request.post({
uri: httpUrlForTransaction,
json: {statements: [{
statement: 'MATCH (n:Show {id:{id}})<-[:BUYS]-(m) RETURN n.name, count(distinct m)',
parameters: param}]}
},
function (err, res, body) {
if (err) {
console.log(err);
return callback(err)
} else {
return callback(null,body)
}
}).auth('neo4j', password, true);
}
[EDITED]
By changing the second console.log() call to output the data as JSON, you can display more details about what you are actually getting back: console.log("%j", res);. The result is probably in that Object.
Additional issue
This may or may not not solve the issue you are asking about, but you do have a logic error with respect to error handling.
async.map() requires that its callback be called once for every item in the array. But in your code, if the anonymous callback passed to getClientsNb() is passed an err value, it returns without ever calling callback.
This code fixes the above issue:
async.map(
arrayOne,
function(item, callback){
getClientsNb({id:item}, function (err, res) {
if (err) { console.log(err); return callback(err); }
console.log(res.results[0].data); //1
callback(null,res.results[0].data);
});
},
function(err,res) {
if (err) return console.log(err);
console.log(res); //2
}
)
I have an array of documents with unique _id and I want to insert them to my database. Some of them already in db, and for those I want to update an array property (push in array an item). All of this I need to make asyncronuosly, so after all inserted/updated I want to write response back (with callback) to client than all ok or write an error. After googling on subject I've found this solution with async module I've tried to implement it for my case. Now my code looks like this:
function processUsers(arr, listName, callback) {
var users = global.db.collection('vkusers');
var q = async.queue(function(task, cb) {
console.log('upsert butch');
users.insert(task.doc, function(err, doc) {
if (err) {
users.update({
_id : task.doc._id
}, {
$addToSet : {
mLists : listName
}
}, function(error, result){ console.log(error); console.log(result); });
}
});
}, arr.length);
for ( var doc in arr) {
q.push({
doc : arr[doc]
}, function(err) {
if (err)
callback(err, null);
})
}
q.drain = function() {
// this is the queue's callback, called when the queue is empty,
// i.e. when all your documents have been processed.
console.log('drain');
callback(null, { result: "success", upserted: arr.length });
}
}
Callback has signature callback(error, result), arr - my array of documents. I've tested it and with database everything is OK, i am getting the right result. But callback, and q.drain never fired!
You need to call async.queue's callback (cb in your code) when your insert/update is complete. Something like this:
var q = async.queue(function(task, cb) {
console.log('upsert butch');
users.insert(task.doc, function(err, doc) {
if (err) {
users.update({
_id : task.doc._id
}, {
$addToSet : {
mLists : listName
}
}, function(error, result) {
console.log(error);
console.log(result);
cb(error); // Update finished; call cb and pass in "error" so that it can bubble up if it exists
});
} else {
cb(); // Insert succeeded; call cb
}
});
}, arr.length);
I am trying to number the id's of my documents with node and mongodb. I am getting a 500 internal server error: 'Cannot read property 'seq' of null.
// submit a ticket - this is returning a 500 error - not updating ID
router.post('/ticketform', function(req, res){
var db = req.db;
function getNextSequence(name, callback){
db.counters.findAndModify(
{
query:{ _id:name},
update:{$inc:{seq:1} },
new:true
}, callback
);
}
getNextSequence('ticket', function(err, obj) {
if (err) console.error(err);
db.users.insert(
{
'_id': obj.seq,
'firstname':req.body.firstname,
'lastname':req.body.lastname,
'email':req.body.email,
'phone':req.body.phone,
'issue':req.body.issue
}, function(err,docs) {
if (err) console.error(err);
console.log(docs);
res.end();
});
});
});
You appear to be using the node native driver in which the syntax is a bit different from the mongodb shell. The .findAndModify() function in particular works quite differently.
As a complete working example for you to work into your application there is this code, along with the usage of the async module make the logic look a little cleaner:
var async = require("async"),
mongodb = require("mongodb"),
MongoClient = mongodb.MongoClient;
MongoClient.connect('mongodb://localhost/test',function(err,db) {
async.waterfall(
[
function(callback) {
db.collection("counters").findAndModify(
{ "_id": "ticket" },
[],
{ "$inc": { "seq": 1 } },
{ "upsert": true, "new": true },
function(err,doc) {
callback( err, doc.seq );
}
);
},
function(seq, callback) {
var doc = { "_id": seq };
db.collection("users").insert(
{ "_id": seq },
function(err, doc) {
callback( err, doc );
}
);
}
], function( err, result ) {
console.log( result );
}
);
});
The parameters on the function are the "query", "sort" which is an array and required even if blank, then the "update" document, "options" in which you want the updated document returned as well as "upsert" to create a new document where no matching document exists,
and finally the callback.
The async waterfall allows you to "pass through" results without embedding your functionality within the callback of the method you use to get the sequence. You don't need to do it that way, but the code looks a little cleaner and direct in it's purpose.
Alternately there are options such as mongoose if you want to use that which has a helper function in .findOneAndUpdate(). You might find connection management a little easier with that library, but it is up to you.
You're probably referring to this tutorial.. In the example they are showing the implementation in the MongoDB shell, where findAndModify is synchronous. As JohnnyHK pointed in the comments, findAndModify in Node.js is asynchronous and the result is returned in the callback.
In Node.js you would do something like this:
function getNextSequence(name, callback){
db.counters.findAndModify(
{ "_id": "ticket" },
[],
{ "$inc": { "seq": 1 }},
{ "new": true, "upsert": true },
callback
);
}
getNextSequence('ticket', function(err, obj) {
if (err) console.error(err);
db.users.insert(
{
'_id': obj.seq,
'firstname':req.body.firstname,
'lastname':req.body.lastname,
'email':req.body.email,
'phone':req.body.phone,
'issue':req.body.issue
}, function(err,docs) {
if (err) console.error(err);
console.log(docs);
res.end();
});
});
You should also check the documentation for the command to better understand the options.