Populate an array with multiple mongo queries [duplicate] - node.js

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 5 years ago.
I'm having a problem with a callback mess.
In my nodejs app, I'm trying to get an array of JSON Objects returned by a mongoDB request. I don't know why, but it don't populate as I want.
I suspect a problem of asynchronous results/callback mess.
var fruits = ["Peach", "Banana", "Strawberry"];
var finalTab = [];
fruits.forEach(function(fruit) {
db.collection('mycollection').distinct("column1", {"column2":{$regex :fruit}}, (function(err, result) {
finalTab[fruit] = result;
console.log(result); // -> display the desired content
db.close();
if (err) throw err;
}));
});
console.log(finalTab); // -> []
Thanks by advance for help.
EDIT :
As I need all results returned by my db.collection...functions... I'm trying to add these async commands to a queue, execute it and get a callback function.
I think that async nodejs module can help.
Can someone tell me how to do this in a ForEach() ?

The line finalTab[fruit] = result; will not help because fruit there is not index. You need to use index in forEach() as follows -
var fruits = ["Peach", "Banana", "Strawberry"];
var finalTab = [];
fruits.forEach(function(fruit, index) {
db.collection('mycollection').distinct("column1", {"column2":{$regex :fruit}}, (function(err, result) {
finalTab[index] = result;
console.log(result); // -> display the desired content
db.close();
if (err) throw err;
}));
});
console.log(finalTab); // -> []

Related

MongoDB returning a null, but query works separately

In a post function, I am trying to retrieve the nth activity of a user (since I have a dropdown that return the index number of the activity). When I run the query
collection.find({'local.email':req.user.local.email},
{'local.activities':{$slice : [currActivity,1]}});
I receive the correct activity object in Robo3T.
But, when I call the same query in Node inside a post function, it returns an undefined.
app.post('/addlog',function(req,res){
var currActivity = req.body.curAct;
var score = req.body.score;
var comment = req.body.reason;
mongoose.connect('mongodb://****:****#ds044907.mlab.com:44907/intraspect',function (err, database) {
if (err)
throw err
else
{
db = database;
var collection = db.collection('users');
var retrievedAct = collection.find({'local.email':req.user.local.email},
{'local.activities':{$slice : [currActivity,1]}}).toArray().then(console.log(retrievedAct));
if (retrievedAct.length > 0) { printjson (retrievedAct[0]); }
console.log(currActivity);
console.log(retrievedAct[0]);
// console.log(req.body.newAct);
collection.update({'local.activities.name':retrievedAct[0]},
{$push: {'local.activities.log' : {
comments: comment,
score: score,
log_time: Date.now()
}}})
.then(function(){
res.redirect('/homepage');
})
.catch(function() {
console.log('Error');
});
}
});
});
I checked that the currActivity variable does infact contain the integer value for the nth activity.
If you want the result of collection.find().toArray(), as specified in the docs, you have two options:
Passing a callback to .toArray() like you did with mongoose.connect()
Using the Promise that it returns if you don't pass a callback
Now you are doing neither of them.
Also, you are mixing callback style and Promises in your code. I recommend you unificate your code. If you are using a Node.js version bigger than 8, using async/await could be nice, it makes it simpler.

In node.js how do i fetch the data of mongodb find() outside the function? [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
var historyQuesn = [];
db.collection('history_QUESTIONS').find({}).toArray().then((docs)=>{
var historyquesn = JSON.stringify(docs,undefined,2);
var historyquesn_parse = JSON.parse(historyquesn);
historyQuesn = historyQuesn.concat(historyquesn_parse);
},(err)=>{
console.log(err);
});
I want to make use of the array returned by the above query in another functions. I want to make use of the documents returned by the db.find() method in some another functions using nodejs! Basically i want to use the vlaue of 'historyQuesn' in another functions. Please Help!
Since the result of Your query will arrive to historyQuesn array when it's finished, so probably you call operation on data before the database query has finished. In Node.js all I/O operations are performed asynchronously thus Node goes further and execute Your code while it waits for the result of that query.
Possible solution is to pass a callback function that gets executed after the database query has finished. Quick example:
function queryCollection(collection, callback) {
collection.find({}).toArray(function(err, result) {
if (err) {
console.log(err);
} else if (result.length > 0) {
callback(result);
}
});
}
queryCollection(collection, function(result){
console.log(result);
// Proceed with Your result here
});
I recommend to read about asynchronous programming if You would like to use Node.js

Is this is happening because of the asynchronous nature of Node.js or is there any alternate way to achiece this?

This is what I am trying to do.
I have an empty array
var send_data = [] ;
and I am using "sync-each" npm library of node.js before that I was doing the iterations using the map callback function but got stuck in the same situation.
Here's my code.
var each = require('sync-each');
client.execute(someQuery,[value],(err,data) => {
var items = data.rows;
each(items,(items,next) => {
// here I am performing some if-else queries and some Cassandra database queries and then pushing the value to my array send_data.
if(items.type == true) {
send_data.push({ value: items.message,flag:true });
}else{
send_data.push({value:items.message,flag:false});
}
},(err,transformedItems)=>{
if(err){
console.log(err);
}
});
});
My programs runs fine without getting any error but when I consoles the final output I get unsoreted list of array values like
[{value:1},{value:3},{value:2},{value:4}]
Is there's a way to correct this?
You can use the map function which makes more sense for your case:
var items = [1,2,3,4];
var send_data = items.map((item)=>({value:item}));
console.log(send_data);

Why I have different results for 'same' thing? [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I need to mention that I'm new to Node.js in general but I'm not sure why for the following code will give me different outputs in console for questions and allQuestions variable ?
var models = require('./models')(mongoose);
var query = models.Question.find({});
var questions = Array();
query.exec(function(err, allQuestions){
//catch the error;
questions = allQuestions;
console.log(allQuestions);
});
console.log(questions);
Output of questions variable will be only: Mongoose: questions.find({}) { fields: undefined } while allQuestions will contain all the questions from database.
I need to know why ?
Also I need that my question variable contains allQuestions from database.
Thats because query.exec() runs the function you passed as parameter asynchronously and the last line console.log(questions); will be executed before the callback is.
If you need the value of questions, then use another callback:
var models = require('./models')(mongoose);
var query = models.Question.find({});
var questions = Array();
query.exec(function(err, allQuestions){
//catch the error;
questions = allQuestions;
console.log(allQuestions);
done();
});
function done() {
console.log(questions);
// handle `questions` here ...
}

Mongoose schema does not save inside async.forEach loop

First post here, so apologies if I get things wrong...
I'm creating some standalone code to read a folder structure and return all .mp3 files in an Array. Once this has been returned I then loop through the array and for each item I create a Mongoose Object and populate the fields, before saving the object with .save()
I am looping through the array using async.forEach - and while it does loop through all items in the Array they do not save, and there is no error produced to help me identify what is wrong.
If I move the logic of the loop elsewhere then the MP3s are stored in the mongodb database - if I have the example shown nothing is saved.
var saveMP3s = function(MP3Files, callback) {
console.log('start loop -> saving MP3s');
async.forEach( MP3Files, function(mp3file, callback) {
newTrack = new MP3Track();
newTrack.title = mp3file.title;
newTrack.track = mp3file.track;
newTrack.disk = mp3file.disk;
newTrack.metadata = mp3file.metadata;
newTrack.path = mp3file.path;
console.log('....:> Song Start: ');
console.log(newTrack.title);
console.log(newTrack.track);
console.log(newTrack.disk);
console.log(newTrack.metadata);
console.log(newTrack.path);
console.log('....:> Song End: ');
newTrack.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('saving Track: '+ newTrack.title);
callback();
}
});
}, function(err) {
if (err) { console.log(err); }
});
console.log('end loop -> finished saving MP3s');
};
The trouble I have is that when the code is NOT in the async loop the code works and the MP3 is saved in the MongoDB database, inside the async code nothing is saved and no errors are given as to why.
I did try (in an earlier incarnation of the code) create the objects once I had read the metadata of the MP3 files - but for some reason it would not save the last 2 objects in the list (of 12)... So I've rewritten it to scan all the items first and then populate mongoDB using mongoose from an array; just to split things up. But having no luck in finding out why nothing happens and why there are no errors on the .save()
Any help with be greatly appreciated.
Regards,
Mark
var saveMP3s = function(MP3Files, callback) {
console.log('start loop -> saving MP3s');
async.forEach( MP3Files, function(mp3file, callback) {
var newTrack = new MP3Track(); // <--- USE VAR HERE
newTrack.title = mp3file.title;
newTrack.track = mp3file.track;
newTrack.disk = mp3file.disk;
newTrack.metadata = mp3file.metadata;
newTrack.path = mp3file.path;
console.log('....:> Song Start: ');
console.log(newTrack.title);
console.log(newTrack.track);
console.log(newTrack.disk);
console.log(newTrack.metadata);
console.log(newTrack.path);
console.log('....:> Song End: ');
newTrack.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('saving Track: '+ newTrack.title);
callback();
}
});
}, function(err) {
if (err) { console.log(err); }
});
console.log('end loop -> finished saving MP3s');
};
I suspect that the missing var keyword is declaring a global variable and you are overriding it on each iteration of the loop. Meaning, before the first newTrack can complete it's async save operation, you've already moved on in the loop and overridden that variable with the next instance.
Also, in async.forEach you MUST invoke the callback when the operation is completed. You are only calling it if the record saves successfully. You should also be calling it if an error occurs and pass in the error.
Finally, the callback argument to your saveMP3s function never gets called at all. The call to callback() inside the newTrack.save function only refers to the callback argument passed into the anonymous function by async.forEach.
SOLVED
Hi,
I ended up solving it by having the async loop higher up the in the logic so the saveMP3s function was called from within the async loop itself.
Thank you all for your thoughts and suggestions.
Enjoy your day.
mark
(not allowed to Accept my answer until tomorrow, so will update the question status then)

Resources