PUT request in Restify API, NodeJS, MongoDB - node.js

I am trying to write a PUT request for my API. I'm using restify to build the API.
I keep getting the errors, could you please help?
//PUT (Update) Items
app.put('/items/:item_id', function(req, res){
var query = Item.where({_id: req.params.item_id});
query.findById(req.params.id, function (err, items) {
item.name = req.body.name;
item.description = req.body.description;
item.url = req.body.url;
req.item.save(function (err) {
if (!err) {
console.log("updated");
} else {
console.log(err);
}
res.send(204, item);
});
});
I tried testing it using POSTMAN client and I get this error
{
"code": "InternalError",
"message": "Object #<Query> has no method 'findById'"
}
Thanks.

The findById method internally maps to find with the parameter {_id: }
You can use either:
Item.find({_id: req.params.item_id}, function (err, items) {
});
or
Item.findById(req.params.item_id, function (err, items) {
});
Both are the same thing. The reason is because when you write
var query = Item.where({_id: req.params.item_id});
A query object is returned, on which the findById method cannot be called. It can only be called on the Item model.
If you are trying to combine queries, I would suggest combining them at the filter level or use aggregation.

Related

Routing function Express.js and retriving data from json

I have a problem with a routing function in express.
I call from firebase realtime database , the JSON has a lot of nested data and I would like to retrieve it with a for loop.
router.get('/admin_tavoli', async (req, res) => {
try {
var lista_tavoli = await firebase().ref('tavoli').once('value');
var lista_tavoli_val = lista_tavoli.val();
for(var i in lista_tavoli_val){
console.log(lista_tavoli_val[i].comanda.tavolo);
}
res.send('ok');
} catch (err) {
res.json({ message: err })
}
});
If I keep to the first level to JSON for example
for(var i in lista_tavoli_val){
console.log(lista_tavoli_val[i].comanda);
}
there are no problems.
But if I go deeper to JSON
for(var i in lista_tavoli_val){
console.log(lista_tavoli_val[i].comanda.tavolo);
}
the execution of the program goes in error, but the strange thing is that in the terminal I see the correct data.
Why does this happen?
thanks to all for the help

Pushing Mongoose Results into Array

I am trying to get results from my "Books.find" and push it into my books array. I want to then res.send it.
I suspect this has something to do with some kind of asynchronous and scope rubbish.
What's the solution?
This is currently my code.
exports.timeline = function(req, res) {
var Followers = mongoose.model('Follow');
Followers.find({'follower': req.user.username}, function(err, followerResult) {
var name = [req.user.username];
var books = [];
function addName(username) {
name.push(username);
}
for(var user in followerResult) {
addName(followerResult[user]['followed']);
}
function getDataByUsername(username) {
function addBookArray(result) {
books.push(result);
return result;
}
var Books = mongoose.model('Book');
Books.find({'username': username}).exec(function (err, result) {
addBookArray(result);
});
}
for(var usernames in name) {
getDataByUsername(name[usernames]);
}
console.log(books);
res.send(books);
});
}
You're right, the problem is that Find is asynchronous and you send your response before you receive the result.
To deal with this kind of issues, you have several choices:
The powerful package Async to organize your async loops
The aggregation of MongoDB to let your DB join your data
Node Js is asynchronous . Your code is never wait for your query result.
Following are some options you can try :
use Async npm package
use Promise
Promise example :-
Promise.all([qry1, qry2]).then(res=>{ console.log(res) }).catch(err=>{console.log(err);})
here qry1 and qry2 are your mongo query
If you don't want to work with the async package, you can try to work with the $in functionality of mongoose and mongodb. As in, you get the list of users, and then find the list of books whoose userid is inside the user list.
Something along the line of :
exports.timeline = function(req, res) {
var Followers = mongoose.model('Follow');
Followers.find({'follower': req.user.username}, function(err, followerResult) {
var name = [req.user.username];
var books = [];
function addName(username) {
name.push(username);
}
for(var user in followerResult) {
addName(followerResult[user]['followed']);
}
Books.find({"username" : { $in: name }}).exec(function (err, books) {
console.log(books);
res.send(books);
});
});
}
Hope this helps.

getting specific item from query answer mongodb node

I was wondering if there is a way I can get a part of an object in mongo using node. For example, it would be great if I could log say the email that is being added, by using something like console.log(result.email) to get the email part of my response. Does anyone know how to do this?
Ok so I have found a way to do this. It will not work on the .find function for some reason, but will work on .findOne and .sort
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("db");
let query = {
username: "username",
key: "key"
};
dbo.collection("keys").findOne(query, (function(err, result) {
var lengthboi = result.length;
console.log(result)
if (lengthboi === 1) {
//do stuff
} else {
}
}));
});

Node.js callback unexpected behaviour with Mongoose

I am a nodejs beginner and I ran into some callback behaviour that I don't understand. I am using an Express router to write Mongoose objects to Mongodb using a POST request. In the body of the request I am passing in a nested json structure with two fields - jobDetails and examples. The data in jobDetails is used to create a Job Mongoose object and the data in examples is used to create several Example Mongoose objects. The Job and Example objects are linked in that a Job contains a list of Example objects in one of it's fields.
The way I tried to implement this was with callbacks in the following way. Basically I save the Job object to mongo first, then iterate over the examples - each time creating an Example object and linking it to the job via the .job field and also saving the Example object to mongo. Then in the callback to the Example object save function I updated the Job object with the new Example object and saved the updated version to mongo.
router.post('/jobs', function (req, res, next) {
var job = new Job(req.body.jobDetails);
var examples = req.body.examples;
console.log("JOB DETAILS");
console.log(req.body.jobDetails);
console.log("EXAMPLES");
console.log(req.body.examples);
//save job
job.save(function (err, job) {
console.log(err);
});
//save examples
for(i=0; i<examples.length;i++){
var eg = new Example({content: examples[i]});
eg.job=job;
eg.save(function (err, eg){
job.examples.push(eg);
job.save(function(err, job){
console.log(err);
});
console.log(err);
});
}
});
This did not perform as I would expect. Specifically, double the number of examples were actually saved to mongo with several duplicates and some missing. I understand that callbacks are asynchronous but to me that still doesn't explain why double the number of examples would be saved and some would be duplicated and some would be missing.
I eventually got it to work correctly without using callbacks at all in the following way.
router.post('/jobs', function (req, res, next) {
var job = new Job(req.body.jobDetails);
var examples = req.body.examples;
console.log("JOB DETAILS");
console.log(req.body.jobDetails);
console.log("EXAMPLES");
console.log(req.body.examples);
//save job
job.save(function (err, job) {
console.log(err);
});
//save examples
for(i=0; i<examples.length;i++){
var eg = new Example({content: examples[i]});
eg.job=job;
eg.save(function (err, eg){
console.log(err);
});
job.examples.push(eg);
job.save(function(err,job){
console.log(err);
});
}
});
And I'm not sure if this is the optimal solution either. But I would like to know why my original approach resulted in the unintended behaviour.
This should work..
router.post('/jobs', function(req, res, next) {
var job = new Job(req.body.jobDetails);
var examples = req.body.examples;
console.log("JOB DETAILS");
console.log(req.body.jobDetails);
console.log("EXAMPLES");
console.log(req.body.examples);
//save job
job.save(function(err, result) {
if (!err) {
//save examples
for (i = 0; i < examples.length; i++) {
var eg = new Example({
content: examples[i]
});
eg.job = job;
eg.save(function(err, eg) {
job.examples.push(eg);
job.save(function(err, job) {
if (!err)
job.examples = [];
});
console.log(err);
});
}
}
});
});
I would suggest you use a library like async to perform such save operations in a step by step manner. Follow this approach for better readability of code and better results
var async = require('async');
router.post('/jobs', function(req, res, next) {
var job = new Job(req.body.jobDetails);
var examples = req.body.examples;
var savedExamples = [];
console.log("JOB DETAILS");
console.log(req.body.jobDetails);
console.log("EXAMPLES");
console.log(req.body.examples);
async.eachSeries(examples, function iteratee(example, callback) {
var eg = new Example({
content: example
});
eg.job = job;
eg.save(function(err, savedEg) {
if(!err) {
savedExamples.push(savedEg);
}
callback(err)
});
}, function(err) {
if(err) {
//handle errors
}
job.examples = savedExamples;
job.save(function(err,job) {
if(err) {
//handle errors
}
//success callback
});
});
});
Using this approach you will have to call the save function for job only once after all other operations are completed. If an error is triggered at any point the whole flow is stopped. For more info regarding async library refer this!

Make Node.js code synchronous in Mongoose while iterating

I am learning Node.js; due to asynchronous of Node.js I am facing an issue:
domain.User.find({userName: new RegExp(findtext, 'i')}).sort('-created').skip(skip).limit(limit)
.exec(function(err, result) {
for(var i=0;i<result.length;i++){
console.log("result is ",result[i].id);
var camera=null;
domain.Cameras.count({"userId": result[i].id}, function (err, cameraCount) {
if(result.length-1==i){
configurationHolder.ResponseUtil.responseHandler(res, result, "User List ", false, 200);
}
})
}
})
I want to use result in Cameras callback but it is empty array here, so is there anyway to get it?
And this code is asynchronous, is it possible if we make a complete function synchronous?
#jmingov is right. You should make use of the async module to execute parallel requests to get the counts for each user returned in the User.find query.
Here's a flow for demonstration:
var Async = require('async'); //At the top of your js file.
domain.User.find({userName: new RegExp(findtext, 'i')}).sort('-created').skip(skip).limit(limit)
.exec(function(err, result) {
var cameraCountFunctions = [];
result.forEach(function(user) {
if (user && user.id)
{
console.log("result is ", user.id);
var camera=null; //What is this for?
cameraCountFunctions.push( function(callback) {
domain.Cameras.count({"userId": user.id}, function (err, cameraCount) {
if (err) return callback(err);
callback(null, cameraCount);
});
});
}
})
Async.parallel(cameraCountFunctions, function (err, cameraCounts) {
console.log(err, cameraCounts);
//CameraCounts is an array with the counts for each user.
//Evaluate and return the results here.
});
});
Try to do async programing allways when doing node.js, this is a must. Or youll end with big performance problems.
Check this module: https://github.com/caolan/async it can help.
Here is the trouble in your code:
domain.Cameras.count({
"userId": result[i].id
}, function(err, cameraCount) {
// the fn() used in the callback has 'cameraCount' as argument so
// mongoose will store the results there.
if (cameraCount.length - 1 == i) { // here is the problem
// result isnt there it should be named 'cameraCount'
configurationHolder.ResponseUtil.responseHandler(res, cameraCount, "User List ", false, 200);
}
});

Resources