FindOne in mongoose returns undefined - node.js

When im consoling all the data int he database using Find method, an object with Title:'day1' is present in it but when I perform findOne operation I get undefined as output.
Please help me.
Post.findOne({ Title: 'day1'}).then(function(err, result){console.log(result)});

Use the following query instead
Post.findOne({ Title: 'day1'},function(err,data)
{
if(err)
{ res.send(err)}
else if(data)
{res.send(data)}
})

It is because you mixed up callback with Promise..
If you will use Callback method you can use the following code:
Post.findOne({Title: 'day1'}, (err, data) {
if (err) {
return res.status(404).send(err); // If there is an error stop the function and throw an error
}
res.status(200).send(data) // If there is no error send the data
})
If you are going to use the promise method:
Post.findOne({Title: 'day1'})
.then(data => res.status(200).send(data)) // Send data if no errors
.catch(err => res.status(404).send(err)) // Throw an error if something happens

Related

Struggling with calling a function that uses promises in node.js

I am struggling with some code... The 2 examples below I would think would work the same but the second example throws an error? I am also struggling to figure out the error, it's not bubbling up? Admittedly I am not a seasoned node developer so any guidance would be much appreciated! If it's relevant the create method in the module is calling the sequelize create.
This works
var p1 = deliverabiltyConfigs.create2(cfgObject);
return Promise.all([p1]).then(function([res1]) {
res.json({result: res1})
});
This does not
deliverabiltyConfigs.create2(cfgObject).then(res1 =>{
res.json({result: res1})
})
Here is the function that I am calling in a controller module
exports.create2 = (dConfig) => {
DeliverabilityConfig.create(dConfig)
.then(data => {
return data
})
.catch(err => {
return {
message:
err.message || "Some error occurred while createing this config."
};
});
};
The create2 function always returns null, so neither invocation will work. Promise.all([p1]) hides the problem, returning a promise to perform an array of no promises.
create2(cfgObject).then(res1 =>{ attempts to invoke then() on null, generating a more obvious error. But neither way works.
Fix by deciding which promise syntax you want, using each as follows:
Using original promise syntax....
exports.create2 = dConfig => {
// note the return
return DeliverabilityConfig.create(dConfig)
.catch(err => {
const message = err.message || "Some error occurred while createing this config.";
return { message };
});
};
// caller
deliverabiltyConfigs.create2(cfgObject).then(result =>{
res.json(result);
})
With recent syntactic sugar...
exports.create2 = async (dConfig) => {
try {
// its fine to not await here, since the caller will await
// but just to illustrate how you might perform more async work here...
return await DeliverabilityConfig.create(dConfig);
} catch (err) {
const message = err.message || "Some error occurred while createing this config."
return { message }
}
}
// caller
var result = await deliverabiltyConfigs.create2(cfgObject);
res.json(result);
Use Promise.all() to run >1 promise concurrently. You've only got one promise in the OP, so no reason for it here.

MongoDB How to catch errors in deleteMany

I have looked at MongoDB documentation for deleteMany() but it seems the only error it throws is WriteConcernError.
I am using Insomnia to make my requests.
Here is my request:
DELETE HTTP://localhost:5000/api/users/delete/usernames?usernames=["a","b","c"]
As you can see I have an array in query string
so I pass that to my function
# user.controller.js
function _deleteByUsernames(req, res, next) {
userService.deleteByUsernames(JSON.parse(req.query.usernames))
.then(() => res.status(200).json({"message": "User(s) successfully deleted!"}))
.catch(err => next(err));
}
# user.service.js
async function _deleteByUsernames(usernames) {
try {
console.log(usernames);
await User.deleteMany({username: {$in: usernames}});
} catch (err) {
throw err;
}
}
I know there no documents with usernames a, b and c
but deleteMany() doesn't return any error something like "Coulnd't find given parameter" etc.
because I don't want to response with "User(s) successfully deleted".
How can I catch that error if there is one.
Or How should I handle that?
You may change your functions to below,
# user.controller.js:
put async/await in function, and add code in try/catch block, and pass res as param in service function deleteByUsernames,
async function _deleteByUsernames(req, res, next) {
try {
await userService.deleteByUsernames(res, JSON.parse(req.query.usernames));
} catch (err) {
next(err);
}
}
# user.service.js:
deleteMany(), This function calls the MongoDB driver's Collection#deleteMany() function. The returned promise resolves to an object that contains 3 properties:
ok: 1 if no errors occurred
deletedCount: the number of documents deleted
n: the number of documents deleted. Equal to deletedCount.
async function _deleteByUsernames(res, usernames) {
let response = await User.deleteMany({ username: { $in: usernames } });
// ERROR
if (response.ok != 1) {
res.status(400).json({ "message": "User(s) not deleted, Something want wrong!" });
}
// SUCCESS
else {
res.status(200).json({
"message": `${response.deletedCount} User(s) successfully deleted out of ${response.n}"
});
}
}
Code is not tested, you can workaround and see what happens!
I think there is no error for no found parameters.
I don't know this is better than nothing for now.
I am not going to mark this as answered because I don't think this is the answer
async function _deleteByUsernames(usernames) {
return await User.deleteMany({username: {$in: usernames}})
.then(result => {
console.log(result);
return (result.deletedCount === 0 ?
"None of the selected user(s) deleted!":
(result.deletedCount !== usernames.length ?
`${result.deletedCount} out of ${usernames.length} selected user(s) successfully deleted!`:
"All selected user(s) successfully deleted!"))
})
.catch(err => {
return `Delete failed with error: ${err}`;
})
}
You can save your delete result in a variable and check for the error
async function _deleteByUsernames(usernames) {
try {
console.log(usernames);
let userDeleteResult = await User.deleteMany({username: {$in: usernames}});
if(!userDeleteResult ){
res.json({status: false, error: 'Some error'}) // or pass the error object here
}
} catch (err) {
throw err;
}
}

What is the proper way of handling errors that are thrown from withing a callback function?

I am developing a NodeJS application and I am using mongoose for saving data into my MongoDB database.
My controller can take a POST request at the /register url with some data. That looks like this:
router.post("/register", async (req: Request, res: Response) => {
const accountModel: IRegistrationAccount = {
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password,
repeatedPassword: req.body.repeatedPassword,
};
try {
registerAccount(accountModel);
res.status(OK).send("Registration successful.");
} catch (err) {
res.status(NOT_ACCEPTABLE).send(err);
}
});
As you can see, I want to return an error message to the user so that they know exactly what went wrong. This is the registerAccount method:
export function registerAccount(accountModel: IRegistrationAccount) {
if (accountModel.firstName.length === 0)
throw "Your first name may not be empty.";
if (accountModel.email.length < 3) throw "Your email is too short.";
if (accountModel.password !== accountModel.repeatedPassword)
throw "The passwords You entered don't match.";
if (accountModel.password.length < 8) throw "Your password is too short.";
const account = new Account(accountModel);
account.save(function (err) {
if (err) return logger.err(err);
return logger.info("Created account.");
});
}
When there is something wrong the the data that the user entered, I return an error message using throw, which is then later caught in the controller. The problem is: how do I know if the callback function inside save threw an error and how do I handle that error? This is my first time working with Node, I tried searching around but can't find a suitable answer.
save method can return Promise so you don't need to use a callback at all:
export async function registerAccount(accountModel: IRegistrationAccount) {
if (accountModel.firstName.length === 0)
throw "Your first name may not be empty.";
if (accountModel.email.length < 3) throw "Your email is too short.";
if (accountModel.password !== accountModel.repeatedPassword)
throw "The passwords You entered don't match.";
if (accountModel.password.length < 8) throw "Your password is too short.";
const account = new Account(accountModel);
await account.save();
}
and add await at the line where you call this function:
try {
await registerAccount(accountModel);
logger.info("Created account.")
res.status(OK).send("Registration successful.");
} catch (err) {
logger.err(err)
res.status(NOT_ACCEPTABLE).send(err);
}
I'd promisify account with util.promisify, and then return the Promise and .catch it in the caller:
return accountSavePromisified().then(() => {
logger.info("Created account.");
});
try {
registerAccount(accountModel)
.then(() => {
res.status(OK).send("Registration successful.");
})
.catch((err) => {
// Catch asynchronous errors (thrown by `.save`):
res.status(NOT_ACCEPTABLE).send(err);
})
} catch (err) {
// Catch synchronous errors (thrown by your validator):
res.status(NOT_ACCEPTABLE).send(err);
}
If you don't care about differentiating errors thrown by .save from errors thrown by your validator, you could also await the call of registerAccount instead of calling .then on it.
You could also consider making the control flow a bit easier to understand by returning error strings from registerAccount instead of throwing, eg return 'Your first name may not be empty.':
const result = registerAccount(accountModel);
if (typeof result === 'string') {
res.status(NOT_ACCEPTABLE).send(result);
return;
}
result.then(() => {
res.status(OK).send("Registration successful.");
})
.catch((err) => {
res.status(NOT_ACCEPTABLE).send(result);
});

(node:2684) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'then' of undefined

I am using .then for first time, instead of .then I use callback function.
Below is my code snippet:
phantom.create().then(function (ph) {
ph.createPage().then(function (page) {
page.open("http://codebeautify.org/xmlvalidator").then(function (status) {
page.render(base_pdf_path + lpnumber + '.pdf').then(function () {
console.log('PDF generated for waybill');
//Insert waybill url in db.
return waybill_url.insertWaybillUrl('Lpsimer', waybillUrl).then(function (waybill_inserted_resp) {
callback(null, true);
}).catch(function (error) {
callback(err_waybill_inserted);
});
});
});
});
});
The above function is calling a function which is as below, this is in another file and called properly filename is waybill.js:
var mongoose = require('mongoose');
var q = require('promised-io/promise');
var WaybillUrlSchema = new mongoose.Schema({
lpnumber: String,
url: String,
waybilltime: Date
});
module.exports = {
insertWaybillUrl: function (lpnumber, url) {
var defer = q.defer();
var waybill_insert = new waybill_url({
lpnumber: lpnumber,
url: url,
waybilltime: new Date()
});
//Save model to MongoDB
waybill_insert.save(function (err, inserted_waybill) {
if (err) {
return defer.reject(err);
}
else {
return defer.resolve(inserted_waybill);
}
});
}
};
Previously I was using this pattern to make callbacks and it was working fine:
waybill_url.insertWaybillUrl('Lpsimer', waybillUrl, function(err, success) {
if (err) {
} else {
}
)}
Now I have to use .then due to usage of phantom code to write PDF and it has made the job cumbersome.
Need suggestion on how I can make callbacks within callbacks.
UPDATE
phantom.create().then(function (ph) {
ph.createPage().then(function (page) {
page.open("http://codebeautify.org/xmlvalidator").then(function (status) {
page.render(base_pdf_path + lpnumber + '.pdf').then(function () {
//Insert waybill url in db.
waybill_url.insertWaybillUrl('Lpsimer', waybillUrl).then(function (waybill_inserted_resp) {
if (waybill_inserted_resp) {
callback(null, true);
}
}).catch(function (error_waybill_url_insert) {
console.log("Error in inserting waybill:" + err_waybill_inserted);
callback(error_waybill_url_insert);
});
}).catch(function (error_render) {
console.log("error_render");
callback(error_render);
});
}).catch(function (error_open) {
callback(error_open);
});
}).catch(function (error_create_page) {
callback(error_create_page);
});
}).catch(function (error_phantom_create) {
callback(error_phantom_create);
});
Now I have added catch for every then as suggested by rsp in his answer, but now I am getting error which I have catched and send to another callback:
Cannot read property 'then' of undefined
I am getting this error where I have added console.log("error_render");
that is where I am calling page.render function of phantom.
My requirement is simple. I want to generate a PDF file using phantom and then I just want to call another function which is in another file waybill_url, function name: waybill_url.insertWaybillUrl. But due to callbacks and asynchronous behaviour this simple calling of two functions is getting cumbersome.
Make sure that you use catch() and not only then() - or two arguments to then(). Otherwise you will not handle errors and you will get that warning - which will be an error, not a warning, in next versions of Node.
See this answer for more info about it:
Should I refrain from handling Promise rejection asynchronously?

Why am I getting a warning when using express app.param to pre-load object with sequelize?

I'm using express app.param to load objects from db (app.param('userId', users.userById);):
exports.userById = function (req, res, next, id) {
return user.findOne({
where: { id: id }
}).then(function (result) {
req.user = result;
next();
}).catch(function (error) {
next(error);
});
};
After that I update the loaded object with the following code.
exports.update = function (req, res) {
var user = req.user;
return user.update({
//update properties
}).then(function () {
res.end();
}).catch(function (error) {
//error handling
});
};
For some reason I get the warning that "a promise was created in a handler but was not returned from it".
I can't see why, but that always happen when I use a routing parameter that uses sequelize before making the actual changes to the database.
What is the correct way to do this?
I'm using sequelize v3.23.3 with Postgres.
EDIT
I changed the code to a more simple example that throws the same warning.
If you forget to return that request promise, the next handler executes immediately with an argument of undefined - which is completely valid for the Promises/A+ spec, but I don't think that it is what you are looking for.
See How to execute code after loop completes for solutions.

Resources