I'm trying to transfer 2 results from 2 callback to 1 lodash function (_.union) using recursive function.
I dont understand what am I doing wrong! I keep getting "undefined".
Here is my code:
EDITED:
My new code with the "promise" technique
the first function that check things in the remote DB-
function findFiles(kw, callback){
if (_.isArray(kw)) {return callback(kw)};
return new Promise((resolve, reject) => {
console.log(kw);
word.aggregate([
{ $match: { keyWord: kw } },
{ $project: { filesFound: '$filesFound.fileName' , '_id':0} },
{ $sort: { fileName: 1 } }
],function(err, obj){
console.log('checked' + kw);
console.log(obj);
if (err) return reject(err);
else
return resolve(obj[0].filesFound);//obj[0].filesFound
})
})
}
The main function:
function searchOperation(query, callback){
var stack=[];
if (!(_.includes(query, 'OR')) && !(_.includes(query, 'AND')) && !(_.includes(query, 'NOT'))){
findFiles(query)
.then((item) => {
console.log(item+'********');
callback(item)
})
.catch((err) => {
console.log(err)
})
}
else{
wordsArr = _.split(query, " ");
console.log("+++++:" + wordsArr);
wordsArr.forEach(function(w){
console.log('first check:'+w);
if(_.isEmpty(stack)){
if(_.includes(w, 'OR')){
console.log('found OR');
var statement = [];
console.log('query is:'+query);
statement = _.split(query, w, 2);
console.log(statement[0]+' , '+statement[1]);
return new Promise((resolve, reject)=>{
resolve(_.union(searchOperation(statement[0]),searchOperation(statement[1])))
})
//ANOTHER OPTION:
// searchOperation(statement[0],function(arr1){
// console.log('arr1');
// console.log('done part 1!');
// searchOperation(statement[1],function(arr2){
// console.log('who called arr2?');
// return(_.union(arr1,arr2));
// })
// });
}
}
})
}
}
now, inside the function findFile() the console.log return what i need. but then I need to use both returned values in another function (union) and it returns undefined.
in the main thread:
searchOperation('Expression1 OR Expression2', function(result){
res.json(result);
})
now i'm sure: something goes WRONG in the recursive function and the async of node...
I need it to work recursively and could get complicate expressions like:
'((A NOT B) AND (C OR D))'
does some know what is the right way to write it either with Promise or async.waterfall ??
thanks in advance!!!
Your code doesn't work because you're trying to get an Async response in a Synchronous fashion.
Look into Promises.
Related
Please help trying to get this function to return value back to my main process. currently everything shows in the console however if I return the object its blank or undefined
const GetSelectDeviceFromDB = () => {
db.all("SELECT * FROM device_list", function (err, rows) {
rows.forEach(function (row) {
console.log(row.device);
return row.device;
});
});
};
module.exports = { GetSelectDeviceFromDB };
OUPUTS:
console.log =. { device1, device2 }
return = undefined and if I add the return to the beginning of the sql statement I get {}
Since all() method is asynchronous and it is using a callback, you can turn your method into a method like this:
const GetSelectDeviceFromDB = () => new Promise((resolve, reject) => {
db.all('SELECT * FROM device_list', (err, rows) => {
if (err) {
reject(err);
}
const devices = rows.map((row) => row.device);
resolve(devices);
});
});
It will return a Promise, so you can call it like this:
GetSelectDeviceFromDB().then(devices => { ... })
Returning from forEach isn't a good idea, returning from another object's method (db.all in you case) isn't either. You need to return exactly in the first scope of the lambda function, somewhere outside of db.all(...). But in this case it's an async method, so you should make your whole function async or a Promise
So, I have a piece of code that makes use of Promises and I am using the bluebird library.
The problem is that my promise gets rejected even if there is no error. It completely skips the .then block even for a simple console.log
Here is the code that makes use of promise:
function returnMeetings(query) {
return new Promise((reject, resolve) => {
Meeting.find(query, (err, foundMeetings) => {
if (err) {
console.log("We have a error")
reject(err);
}
resolve(foundMeetings);
})
})
}
And here is the code that makes use of that returnMeetings function
returnMeetings(query)
.then((data) => {
console.log("here we are")
// while (count < stopAt) {
// let localData = [];
// if (req.params.duration === 'monthly') {
// let {
// date1,
// date2
// } = twoDates(count, count);
// localData = data.filter((el) => {
// if (el.startDate) {
// let localDate = new Date(el.startDate);
// if (localDate >= date1 && localDate <= date2) {
// return el;
// }
// }
// })
// if (localData) {
// data.push({
// data: localData,
// month: count
// })
// }
//
// if (count === stopAt - 1) {
// myEmitter.emit('found all meetings')
// } else {
// count++;
// }
// }
// }
}).catch((err) => {
res.status(500).json({
message: err
})
})
As you can see in the returnMeetings function i have placed a console.log inside the if(err) block, and it never runs, from that I conclude that I didn't receive any error from the mongoose query.
Still, the code completely skips the .then block, and falls into the catch chain. I have a simple console.log inside the then block, and an interesting thing to note is that the value of err in the callback inside catch block is an array of mongodb documents.
Can someone explain, why is my code behaving in this manner?
Thanks for your help.
the order of resolve/reject in your Promise constructor callback is wrong ... the names of the functions are irrelevant, the first is to resolve, the second is to reject ... you are actually rejecting the promise when you call resolve
i.e. you could
return new Promise((fred, wilma) => {
then to resolve the promise, you would call fred(value) and to reject you would call wilma(error)
in other words, the names you give the callback arguments is irrelevant, the position is relevant
change your code as follows:
function returnMeetings(query) {
return new Promise((resolve, reject) => {
Meeting.find(query, (err, foundMeetings) => {
if (err) {
console.log("We have a error")
reject(err);
}
resolve(foundMeetings);
})
})
}
I need to wait an answer from my server to say if the email is already taken or not. But I'm struggling to make this synchronously. In my if statement, typescript says that isCorrectEmail() is a void function (that I can understand but cannot solve). Any idea?
isEmailAvailable(){
return new Promise( (resolve, reject) => {
this.authService.checkemail(this.user.email).then(result => {
let res = <any> result;
if (res.code == 0){
resolve(true);
}
elseĀ resolve(false);
}, (err) => {
reject(false);
});
});
};
isCorrectEmail(){
this.isEmailAvailable().then( (result) => { return result ; } );
};
checkPersonalInfos()
{
if ( this.isCorrectEmail() == true){...}
..
}
You cannot turn an asynchronous call into a synchronous one.
You have two options: move the code which needs the use the resulting value entirely inside a then callback:
checkPersonalInfos()
{
this.isEmailAvailable().then(isAvailable => {
if (isAvailable) { ... }
}
}
Or use the async/await syntax to make it look like synchronous code, but remember it is still asynchronous so other code will run during the await and if you return a result from the function it will be wrapped inside a Promise():
async checkPersonalInfos()
{
if (await this.isEmailAvailable()) { ... }
...
}
You don't actually need your isCorrectEmail() function here as it does nothing at all to the result, but if it did something more complex so it was actually needed then it has to return the Promise:
isCorrectEmail(): Promise<boolean> {
return this.isEmailAvailable().then(result => result);
};
The code is running well until the Promise.all and then is goes right to the catch saying 'then is not defined'.
I've been trying to figure this out without success for hours :(.
Any help are welcome.
Here is a simplified example of code:
// Save
return new Promise((fulfillSave, rejectSave) => {
// Get
this._getObjects().then((object) => {
var promises = [];
// For each value
object.values.forEach((value) => {
promises.push(
// Create promise
new Promise((fulfill, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
})
);
});
// Wait for all promises
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, then((err) => {
// Err
rejectSave(err);
}));
}
}).catch((err) => {
rejectSave(`Error: ${err.message}`);
});
});
Thanks in advance!
Serge.
This is incorrect:
// Wait for all promises
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, then((err) => {
// ^^^^--------------------------- error here
// Err
rejectSave(err);
}));
It's trying to call a freestanding function called then and pass its return value into the then on the object returned by Promise.all.
I think you're trying to hook up a failure handler. If so, you don't say then, you just supply a second function:
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, (err) => {
// Err
rejectSave(err);
}));
But of course, since you're not using the result of that chain and you're just passing the single argument your second function receives into rejectSave, you could just pass rejectSave directly:
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, rejectSave);
If you told us what your overall code is meant to do and what its inputs are, my suspicion is that that code could be a lot simpler. It's common to create and nest promises unnecessarily, and I suspect that's happening here.
For instance, if you just want to do the saves and get back a promise that will resolve when they're all done successfully or reject on the first failure:
return this._getObjects()
.then(objects => Promise.all(objects.map(value => {
return new Promise((resolve, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
});
})));
Or if we give ourselves a helper function for the Mongo bit:
function mongoSavePromise(value) {
return new Promise((resolve, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
});
}
then:
return this._getObjects()
.then(objects => Promise.all(objects.map(mongoSavePromise)));
Avoid the Promise constructor antipattern!
Your whole code should be a simple
return this._getObjects().then(object => {
var promises = object.values.map(value => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
return valueMongoDB.save().catch(err => {
throw 'Error in saving';
});
});
// Wait for all promises
return Promise.all(promises);
}, err => {
throw `Error: ${err.message}`;
});
No unnecessary callbacks, no room for mistakes. Btw, you shouldn't throw strings.
I have a function that returns a Promise, that accesses the database and pulls a few lines out, assigning them to a Javascript variable.
The issue is that my '.then' clause is being triggered even though I know the Promise hasn't resolved:
app.post("/api/hashtag", function (req, res) {
FindPopularRumours().then(function (resolveVar) {
console.log(resolveVar);
console.log();
res.send(resolveVar);
}).catch(function () {
console.log("DB Error!");
res.send("DB Error!");
});
});
And the Promise function:
function FindPopularRumours() {
return new Promise((resolve, reject) => {
var hashtags = [];
var dbPromise;
db.collection(HASHTAGS).find().forEach(function (doc) {
hashtags.push(doc.hashtag);
console.log(hashtags);
});
resolve(hashtags);
});
}
The result output is:
[ ]
['#test1']
['#test1', '#test2']
['#test1', '#test2', '#test3']
As you can see, the first line ('[ ]') should ONLY be executed AFTER the hashtags have been output. But for some reason my code seems to think the Promise has been resolved before it actually has.
EDIT1
As per Ankit's suggestion, I have amended my function to:
function FindPopularRumours() {
return new Promise((resolve, reject) => {
var hashtags = [];
db.collection(HASHTAGS).find({}, function (err, doc) {
if (!err) {
doc.forEach(function (arg) {
hashtags.push(arg.hashtag);
console.log(hashtags);
});
resolve(hashtags);
} else {
return reject(err);
}
});
});
}
This still returns the same output response as before (e.g the 'then' clause is running before the promise itself).
My POST function is still the same as before.
The db.collection.find() function is async, so you have to resolve the promise inside the callback for that, something like
function FindPopularRumours() {
return db.collection(HASHTAGS).find().toArray().then( (items) => {
return items.map( doc => doc.hashtag);
});
}
takes advantage of the Mongo toArray() method, that returns a promise directly
Please note that db.collection(HASHTAGS).find() is an asynchronous call. So, your promise is resolved before database query returns. To solve this problem, you need to re-write your database query as follows:
function FindPopularRumours() {
return new Promise((resolve, reject) => {
var hashtags = [];
var dbPromise;
db.collection(HASHTAGS).find({}, function(err, doc){
if(!err){
doc.forEach(function (arg) {
hashtags.push(arg.hashtag);
console.log(hashtags);
});
resolve(hashtags);
}else{
return reject(err);
}
});
});
}
Hope the answer helps you!