NodeJS API GET by Id. How to detect item not found? - node.js

I'm developing a GET endpoint to fetch elements from a database(dynamoDB). I'm using Swagger to define the data model in my api. This is the operationId method in my controller:
getInvoiceConfigById: function(req, res) {
var myId = req.swagger.params.id.value;
// InvoiceConfig is a dynamoDb model
// providerId attribute is the unique key of the db table
InvoiceConfig.scan('providerId')
.eq(myId)
.exec(function (err, config) {
if (err) {
console.log("Scan InvoiceConfig error");
throw err;
}
res.status(200).send(config);
});
}
I would like to send a 404 message if the id was not found.
I've noticed in swagger-ui that the body of the response comes empty
Response Body
[]
when the id is not found in the db.
How can I detect in my code when id was not found? I've tried to check if the body of the response is empty:
if(!(config.body))
but this doesn't work because the body is not null

You can check the count of config at server side, if config count is 0 the send desire response code 404 else return 200 response code with data as shown below
getInvoiceConfigById: function(req, res) {
var myId = req.swagger.params.id.value;
// InvoiceConfig is a dynamoDb model
// providerId attribute is the unique key of the db table
InvoiceConfig.scan('providerId')
.eq(myId)
.exec(function (err, config) {
if (err) {
console.log("Scan InvoiceConfig error");
throw err;
}
if (config.length == 0){
res.status(404).end();
} else {
res.status(200).send(config);
}
});
}

Try adding a length check in your callback, like so:
getInvoiceConfigById: function(req, res) {
var myId = req.swagger.params.id.value;
// InvoiceConfig is a dynamoDb model
// providerId attribute is the unique key of the db table
InvoiceConfig.scan('providerId')
.eq(myId)
.exec(function (err, config) {
if (err) {
console.log("Scan InvoiceConfig error");
throw err;
}
if(typeof config === 'array' && 0 < config.length){
res.status(200).send(config);
} else {
res.status(404).send();
}
});
}
I would also suggest that you should simply use the getItem query instead of scan:
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#getItem-property

Since the config object keys value is one when result is not found so what you can do is check the length of keys of that object like this :
if ( Object.keys(config).length == 1 )return res.status(400).send("Error 404");

Related

node js SQL Insert Query with Constructor / JSON text as values parameter

First real app and I'm stuck trying to insert a new row into SQL.
//This is the API endpoint
Sponsor.create = (newSponsor, result)=> {
var sqlStmt = 'insert into sponsors (SponsorName, SponsorState, SponsorDesc, pnfpExperience, Status) values ?'
sql.query(sqlStmt, [newSponsor], (err, res)=> {
if(err) {
console.log(" error: ", err);
result(null, err);
}
else{
console.log(res);
result(null, res);
}
});
};
request.body returns the JSON text but not an array of values that can be used in the query. I keep getting a COUNT error or syntax error. I've tried JSON.parse but I get an undefined error. I know there has to be a simple way to convert the JSON text to the right format but I don't know what I'm missing. The "findAll" and "findById" routes work and I can insert static values. I've also tried "newSponsor" with and without brackets. I'll refine the connection method in time but I'm just trying to understand why this doesn't work. Any help is greatly appreciated.
// Controller.js for Reference
exports.create = function(req, res) {
const new_sponsor = new Sponsor(req.body);
//handles null error
if(req.body.constructor === Object && Object.keys(req.body).length === 0){
res.status(400).send({ error:true, message: 'Please provide all required field' });
}else{
Sponsor.create(new_sponsor, function(err, sponsor) {
if (err)
res.send(err);
res.json({error:false,message:"Sponsor added successfully!",data:sponsor});
});
}
};

How to return an object within inside for loop

I want to return "items" which is inside the for loop and also two additional functions."Items" is an object (I would not say variable) which consists of three array elements and that can be more depending on the situation. So I need to return "items" so I can access it outside and I can send it to the client using res.send(). If I send data inside the loop and function, it is returning with an error called "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client". I found the fix for it but on implementing them, nothing is happening. It is throwing me the same error. I was thinking to do it call back function but I am confused about how to use it in this case. Thanks in advance.
router.get("/send" , async (req, res) => {
try {
res.send("hello")
//await sendData()
getCollectionNames()
} catch (error) {
console.log(error);
}
function getCollectionNames(){
MongoClient.connect(url, function(err, db) {
var db = db.db('admin')
mongoose.connection.db.listCollections().toArray(function (err, names) {
for(let index = 0; index < names.length; index ++){
if (err) {
console.log(err);
}
let name = names[index].name
const collection = db.collection(name)
collection.find().toArray(function(err, items){
console.log(items)
})
}
});
})
}
})

Why is my express app returning an empty array?

I am creating a CRUD api with express and mongodb. I have a specific route which queries one collection in my mongo db and retrieves whatever documents match the query criteria. My program then loops through these documents and trys to find the latest cross entry in another collection in my db
exports.findLatestCommitforAllRepos = function(req,res,next){
var githubCommitDataCollection = index.db.collection(githubCommitDataCollectionName);
var enabledRepoCollection = index.db.collection(enabledRepoCollectionName);
var latestCommits = [];
enabledRepoCollection.find({enabled:true}).toArray(function(err,repos) {
if (err) { next(err); }
if (repos.length === 0 || repos === 'undefined') {
res.status(404);
res.send("There are no repos being tracked")
}
else {
repos.forEach(function(enabledRepo) {
var repo = enabledRepo.repo;
var userOrOrg = enabledRepo.userOrOrg;
githubCommitDataCollection.find({repo: repo, userOrOrg:userOrOrg}).sort({commitDate: -1}).limit(1).toArray(function(err,commit) {
if (commit.length === 0 || repos === 'undefined') {
res.send("No commit found for repo " + repo);
}
// console.log(commit[0]);
latestCommits.push(commit[0]);
console.log(latestCommits);
});
});
res.setHeader('Content-Type', 'application/json');
res.status(200);
res.json(latestCommits);
res.end();
}
});
}
This results in an empty array being returned.
You can use the async libary especially the async.waterfall() method when you need to run a tasks array of functions in series, each passing their results to the next in the array.
Consider the following example:
// Include the async package
// Make sure you add "async" to your package.json
async = require("async");
exports.findLatestCommitforAllRepos = function(req,res,next){
var latestCommits = [];
async.waterfall([
// Load all documents
function(callback) {
index.db.collection(enabledRepoCollectionName).find({"enabled": true}).toArray(function(err,repos){
if (err) return callback(err);
callback(null, repos);
});
},
// Get count of documents where price is empty
function(reposData, callback) {
async.each(reposData, function(enabledRepo, callback) {
index.db.collection(githubCommitDataCollectionName)
.findOne({repo: enabledRepo.repo, userOrOrg: enabledRepo.userOrOrg})
.sort({commitDate: -1}).limit(1)
.exec(function(err, commit) {
latestCommits.push(commit);
callback();
});
}, callback);
}
], function(err, result) { //This function gets called after the three tasks have called their "task callbacks"
if (err) return next(err);
res.setHeader('Content-Type', 'application/json');
res.status(200);
res.json(latestCommits);
res.end();
});
});
One minor suggestion in code,
use .findOne instead of .find
Means instead of
githubCommitDataCollection.find({repo: repo, userOrOrg:userOrOrg}).sort({commitDate: -1}).limit(1).toArray(function(err,commit) {
use
githubCommitDataCollection.findOne({repo: repo, userOrOrg:userOrOrg}).sort({commitDate: -1}).exec(function(err,commit) {
It will return only one commit and check console.log(commit) value to check what your are getting as result.
Or Please check share existing documents of githubCommitDataCollection

unable to add property to the json object

I am trying to add status to a response on successful update but I am not able to add the status property to json object of form. Here is my code
apiRouter.post('/forms/update', function(req, res){
if(req.body.id !== 'undefined' && req.body.id){
var condition = {'_id':req.body.id};
Form.findOneAndUpdate(condition, req.body, {upsert:true}, function(err, form){
if (err) return res.send(500, { error: err });
var objForm = form;
objForm.status = "saved successfully";
return res.send(objForm);
});
}else{
res.send("Requires form id");
}
});
and here is the response that I get, notice status is missing
{
"_id": "5580ab2045d6866f0e95da5f",
"test": "myname",
"data": "{\"name\":3321112,\"sdfsd\"344}",
"__v": 0,
"id": "5580ab2045d6866f0e95da5f"
}
I am not sure what I am missing.
Try to .toObject() the form:
Form.findOneAndUpdate(condition, req.body, {upsert:true}, function(err, form){
if (err) return res.send(500, { error: err });
var objForm = form.toObject();
objForm.status = "saved successfully";
return res.send(objForm);
});
Mongoose query result are not extensible (object are frozen or sealed), so you can't add more properties. To avoid that, you need to create a copy of the object and manipulate it:
var objectForm = Object.create(form);
objectForm.status = 'ok';
Update: My answer is old and worked fine, but i will put the same using ES6 syntax
const objectForm = Object.create({}, form, { status: 'ok' });
Another way using spread operator:
const objectForm = { ...form, status: 'ok' }
Try changing res.send(objForm) to res.send(JSON.stringify(objForm)). My suspicion is that the the Mongoose model has a custom toJson function so that when you are returning it, it is transforming the response in some way.
Hopefully the above helps.
Create empty object and add all properties to it:
const data = {};
data._id = yourObject._id; // etc
data.status = "whatever";
return res.send(data);
Just create a container.
array = {};
Model.findOneAndUpdate(condition, function(err, docs){
array = docs;
array[0].someField ="Other";
});

Backbone Node - fetch - server sending only response object but not model ,how can i get model?

Backbone,Node : when i call fetch method, fetch is successful in server but when it sends response back using
res.send(result)
it is not sending(may be) any model or it is sending old model back,and it is sending only response object . Model is what i want, how can i get ?
app.get('/college/colleges/:_id', function (req, res) {
oid = new ObjectID(req.params._id.toString());
return CollegeModel.find({
_id: oid
}, function (err, result) {
if (!err) {
console.log("Fetched college model successfully");
res.send(result);
} else {
console.log("Error : " + err);
res.send(err);
}
});
});
the above code is in node . Below one is in client javascript (in a view).
college_model = new CollegeModel(id)
college_model.fetch({
success = function (model, res, options) {
console.log model // here , new model should come with all new attributes, but old model with only id attribute is appearing here,,,in model format.
console.log res // here, i am getting all required records in objectformat,no problem for this res
}
error = function (model, res, options) {
console.log("Error ");
}
})
thanks
got the answer
instead of sending
res.send(result);
send like this :
res.send(result[0]);
then the result will be fine !

Resources