const isName = req => {
return user
.find({ where: { name: req.body.name } })
.then(row => {
return row == null ? true : false;
});
};
Function isName() doesn't return a value. This simple code row == null ? true : false; doesn't return a value, but I'm sure that's working. What is the reason?
Querying is asynchronous, so make sure you await for the result and send it:
// I guess it's a route handler
const isName = async (req, res) => {
const result = await user
.find({ where: { name: req.body.name } })
.then(row => row === null); // same as row === null ? true : false;
res.send(result);
};
Issue :
return user.find({ // <------ This will return promise not true or false
So you can't make call like isName() and get expected result , promise
should be handled to get the expected result
Solution :
isName().then(isThere => { // <------- To get value you should handle like this
if(isThere) {
} else {
}
})
Related
I don't know If I'm checking for the value of the boolean correctly
what this code does: the user creates a note for himself, his ID is on the note and it needs to belong to a category name that has to be in the category schema ( where my error happens )
exports.postAddNote = (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error("validation failed, entered data is incorrect");
throw error;
}
const content = req.body.content;
const tags = req.body.tags;
const categoryName = req.body.categoryName;
let creator;
const note = new Note({
content: content,
categoryName: categoryName, // work
tags: tags,
creator: req.userId,
});
Category.find()
.select("-_id")
.select("-__v")
.select("-notesId")
.then((categories) => {
console.log(categories); //stripping everything but names off categories
const CategoryExists = categories.some(
(category) => category.name === categoryName
);
console.log(CategoryExists); // ~~~~~~~~~~ this logs correctly
if (CategoryExists === -0) { // ~~~~~~~~~~ what i want: if the value is false
return res.json({ Error: "The category you entered does not exist" });
}
note // ~~~~~~~~~~ the code stops here :/ it doesn't save the note
.save()
.then((note) => {
console.log("saved note");
User.findById(req.userId);
})
.then((user) => {
creator = user;
user.notes.push(note);
return user.save();
})
.then((result) => {
res.status(201).json({
info: {
dateCreated: new Date().toISOString(),
status: "Note Created Successfully",
creator: { _id: creator._id, email: creator.email },
},
});
})
.catch((err) => {
if (!err.statusCode) {
err.statusCode = 500;
}
});
})
.catch((err) => {
console.log(err);
next();
});
};
if (CategoryExists === -0)
should be
if (CategoryExists === false)
or just
if (!CategoryExists)
i believe. did you try that? not sure why you are using -0. the return value for some() is either going to be true or false.
try this:
if (!CategoryExists) {
return res.json({ Error: 'The category you entered does not exist' });
}
I have a controller that basically performs a recursive call to retrieve how categories and their deleted items, but a "category_item" has a property called "next_steps" which is an array of categories, so I need to retrieve those categories and their items as well.
So I made a recursive function, it works, but I need to run something else when it actually ends, how can I do that? here's my code:
const recoveryCategory = async (req, res) => {
try {
const categoryId = req.params.categoryId
const category = await nmCategorySvcV2.getByIdDeleted(categoryId)
if (category === null){
throw new Error("This category is not deleted.")
}
__recoveryRecursive(categoryId)
// run something after
res.json({ success: true, message: "Success." })
} catch (err){
res.json({ success: false, message: err.message })
}
}
const __recoveryRecursive = async (categoryId) => {
const category = await nmCategorySvcV2.getByIdDeleted(categoryId)
if (category === null){
return
}
await nmCategorySvcV2.update(categoryId, { deleted: false })
const categoryItens = await categoryItemSvcV2.getAllItensByCategory(categoryId)
for (let i = 0; i < categoryItens.length; i++) {
const categoryItem = categoryItens[i]
if (categoryItem.deleted == true) {
const item = await itemSvcV2.getByIdNoPopulate(categoryItem.item, categoryItem.page)
if (item.deleted == true) {
itemSvcV2.update(item._id, { deleted: false })
categoryItemSvcV2.updateItensProp(item._id, { deleted: false })
}
const itemPrice = await itemPriceSvcV2.getById(categoryItem.price)
if (itemPrice.deleted == true) {
itemPriceSvcV2.updateObject({ _id: itemPrice._id }, { deleted: false })
}
categoryItemSvcV2.update(categoryItem._id, { deleted: false })
if (categoryItem.next_steps.length > 0){
for (let j = 0; j < categoryItem.next_steps.length; j++){
const categryNextStep = categoryItem.next_steps[j].category
__recoveryRecursive(categryNextStep)
}
}
}
}
}
Just add await before the recursive call because it returns a promise wich must be handled .
I have a function in the middleware file called setSignedInUser which receives a cookie as a parameter. I want to find a user saved in the SignedIn collection with the cookie,retrieve the user's unique id ,search for the user's complete information from the Users collection and return the foundUser which I would like to access in another file where the function is called from.
The middleware file:
const { resolve } = require('path');
const User = require('./Models/User'),
SignedIn = require('./Models/SignedIn');
module.exports = {
setSignedInUser : (cookie)=>{
console.log(cookie)
SignedIn.findOne({secretToken : cookie})
.then(foundSignIn=>{
userId = foundSignIn.userId;
User.findOne({_id : userId})
.then(foundUser=>{
console.log(foundUser) // User is successfully found and loged to the console
return new Promise((resolve , reject)=>{
if(foundUser){
resolve(foundUser);
}else{
reject('error')
}
})
})
.catch(err=>{
console.log(err)
})
})
.catch(err=>{
console.log(err)
})
}
}
I call this function from the index.js file where my route is.
The index.js file:
const middleware = require('../middleware');
router.get('/' , (req , res)=>{
middleware.setSignedInUser(req.cookies.auth_cook)
.then(foundUser=>{
console.log(foundUser)
})
.catch(err=>{
console.log(err)
})
res.render('../views/general/home.ejs' , {user : user})
});
But here I get an error saying Cannot call .then on undefined
What am I missing here? Thankyou
You are not returning anything from your setSignedInUser function, so foundUser is undefined. A correct way would be this:
module.exports = {
setSignedInUser: (cookie) => {
return new Promise((resolve, reject) => {
SignedIn.findOne({
secretToken: cookie
})
.then((foundSignIn) => {
userId = foundSignIn.userId;
User.findOne({
_id: userId
})
.then((foundUser) => {
if (foundUser) {
resolve(foundUser);
} else {
reject('error');
}
})
.catch((err) => {
console.log(err);
reject(err);
});
})
.catch((err) => {
console.log(err);
reject(err);
});
});
},
};
Since you want the result of an inner function you can return a Promise and resolve it with the inner value.
I think it's because you return the new promise inside your 2nd level promise.
Try to pass User.findOne in async like this:
module.exports = {
setSignedInUser : (cookie)=>{
SignedIn.findOne({secretToken : cookie})
.then(async foundSignIn=>{
userId = foundSignIn.userId;
const foundUser = await User.findOne({_id : userId})
if(foundUser){
return foundUser;
} else {
return Promise.reject("error"}
}
})
.catch(err=>{
console.log(err)
})
}
}
I'm not sure but I think you should try this,
try changing declaration of function like this. :
Just replace : with =
setSignedInUser = (cookie)=>{
}
function setUsersDefinitions(data, userID){
let users = new Array();
return new Promise((resolve)=>{
data.forEach(el => {
if (el.id_adder === userID) {
getUserName(el.id_added).then(u => {
users.push({
username: u,
locked: el.locked !== null,
canUnlock: el.locked === userID,
id: el.id_added
})
}).catch(e=>{
console.log(e);
})
} else {
getUserName(el.id_adder).then(u=>{
users.push({
username: u,
locked: el.locked !== null,
canUnlock: el.locked === userID,
id: el.id_adder
})
}).catch(e=>{
console.log(e);
})
}
})
resolve(users);
})
}
The problem is that when i try doing a console.log of the item generated it works but when it call Array.push method, it ignore that command.
What am I doing wrong?
Thanks in advance.
All of this should be done with async/await, and not by wrapping the whole lot in a Promise - it will hugely simplify your code:
async function setUsersDefinitions(data, userID){
let users = new Array();
for(var i=0;i<data.length;i++){
var el = data[i];
var id = (el.id_adder === userID) ? el.id_added : el.id_adder;
var u = await getUserName(id);
users.push({
username: u,
locked: el.locked !== null,
canUnlock: el.locked === userID,
id: id
});
}
return users;
}
(Note: Error handling omitted for brevity)
You should then await this function wherever you call it (must itself be within an async function):
async function doWork(){
var users = await setUsersDefinitions(some_data, some_userID);
console.log(users);
}
I have
Page.findById(pageId).then(page => {
const pageId = page.id;
..
});
My problem is that if no page id is given, it should just take the first available page given some conditions, which is done by
Page.findOne({}).then(page => {
const pageId = page.id;
..
});
but if no page is found, it should create a new page and use this, which is done with
Page.create({}).then(page => {
const pageId = page.id;
..
});
But how do I combine all this to as few lines as possible?
I have a lot of logic going on inside
page => { ... }
so I would very much like to do this smart, so I can avoid doing it like this
if (pageId) {
Page.findById(pageId).then(page => {
const pageId = page.id;
..
});
} else {
Page.findOne({}).then(page => {
if (page) {
const pageId = page.id;
..
} else {
Page.create({}).then(page => {
const pageId = page.id;
..
});
}
});
}
I am thinking I maybe could assign a static to the schema with something like
pageSchema.statics.findOneOrCreate = function (condition, doc, callback) {
const self = this;
self.findOne(condition).then(callback).catch((err, result) => {
self.create(doc).then(callback);
});
};
As per the Mongoose docs:
As per previous SO answer
Model.findByIdAndUpdate()
"Finds a matching document, updates it according to the update arg, passing any options, and returns the found document (if any) to the callback."
In the options set upsert to true:
upsert: bool - creates the object if it doesn't exist. defaults to false.
Model.findByIdAndUpdate(id, { $set: { name: 'SOME_VALUE' }}, { upsert: true }, callback)
Related to Yosvel Quintero's answer which didn't work for me:
pageSchema.statics.findOneOrCreate = function findOneOrCreate(condition, callback) {
const self = this
self.findOne(condition, (err, result) => {
return result ? callback(err, result) : self.create(condition, (err, result) => { return callback(err, result) })
})
}
And then use it like:
Page.findOneOrCreate({ key: 'value' }, (err, page) => {
// ... code
console.log(page)
})
Promise async/await version.
Page.static('findOneOrCreate', async function findOneOrCreate(condition, doc) {
const one = await this.findOne(condition);
return one || this.create(doc);
});
Usage
Page.findOneOrCreate({ id: page.id }, page).then(...).catch(...)
Or
async () => {
const yourPage = await Page.findOneOrCreate({ id: page.id }, page);
}
Each Schema can define instance and static methods for its model. Statics are pretty much the same as methods but allow for defining functions that exist directly on your Model
Static method findOneOrCreate:
pageSchema.statics.findOneOrCreate = function findOneOrCreate(condition, doc, callback) {
const self = this;
self.findOne(condition, (err, result) => {
return result
? callback(err, result)
: self.create(doc, (err, result) => {
return callback(err, result);
});
});
};
Now when you have an instance of Page you can call findOneOrCreate:
Page.findOneOrCreate({id: 'somePageId'}, (err, page) => {
console.log(page);
});
One lines solution with async/await:
const page = Page.findOne({}).then(p => p || p.create({})
If you don't want to add a static method to the model, you can try to move some things around and at least not to have all these callback nested levels:
function getPageById (callback) {
Page.findById(pageId).then(page => {
return callback(null, page);
});
}
function getFirstPage(callback) {
Page.findOne({}).then(page => {
if (page) {
return callback(null, page);
}
return callback();
});
}
let retrievePage = getFirstPage;
if (pageId) {
retrievePage = getPageById;
}
retrievePage(function (err, page) {
if (err) {
// #todo: handle the error
}
if (page && page.id) {
pageId = page.id;
} else {
Page.create({}).then(page => {
pageId = page.id;
});
}
});
The solutions posted here ignore that this pattern is most common when there's a unique index on a field or a combination of fields. This solution considers unique index violation errors correctly:
mongoose.plugin((schema) => {
schema.statics.findOrCreate = async function findOrCreate(key, attrs) {
try {
return await this.create({ ...attrs, ...key });
} catch (error) {
const isDuplicateOnThisKey =
error.code === 11000 &&
Object.keys(error.keyPattern).sort().join(',') ===
Object.keys(key).sort().join(',');
if (isDuplicateOnThisKey) {
const doc = await this.findOne(error.keyValue);
doc.set(attrs);
return await doc.save();
}
throw error;
}
};
});
Usage:
await Post.findOrCreate({ slug: 'foobar' }, { title: 'Foo Bar', body });
try this..
var myfunc = function (pageId) {
// check for pageId passed or not
var newId = (typeof pageId == 'undefined') ? {} : {_id:pageId};
Page.findOne(pageId).then(page => {
if (page)
const pageId = page.id;
else { // if record not found, create new
Page.create({}).then(page => {
const pageId = page.id;
});
}
});
}