var articleFinish;
async.series({
one: function(callback) {
async.eachOf(set, function(tags, index, callback) {
Article.findById(articleId).exec(function(err, article) {
article.weibos[2].text = 'aa'; //success
article.weibos[2].tags = 'aaa'; //success
article.weibos[index].text = tags; //can't set value for next 'article'
article.weibos[index].tags = tags; //can't set value for next 'article'
articleFinish = article;
callback();
});
}, function(err) {
if (err) console.error(err.message);
callback(null, 3);
});
},
two: function(callback) {
Article.findById(articleId).exec(function(err, article) {
article = articleFinish;//can't get value when use the last two statement.
article.save(function(err) {});
});
}
}, function(err, results) {
res.send(results);
});
I want to set the last article's value by a global var.
What should I do?
Related
getting undefined all the time "main.js":
var dbAccess = require('../dao/dbAccess');
dbaInstance = new dbAccess();
var wordPool = dbaInstance.getWordPool();
console.log (wordPool);
and "dbAccess.js" contains:
var DatabaseAccess = function() {}
DatabaseAccess.prototype.getWordPool = function () {
RoundWord.find({},'words decoys', function(err, wordPoolFromDB) {
if (err) throw err;
//console.log(wordPoolFromDB); -working ok
return (wordPoolFromDB);
});
}
module.exports = DatabaseAccess;
why is it not working?
DatabaseAccess.prototype.getWordPool is not returning any result.
Since you are using an asynchronous function, you need do one of these things:
a) Take a callback as parameter and invoke the callback with a result
DatabaseAccess.prototype.getWordPool = function (cb) {
RoundWord.find({}, 'words decoys', function(err, results) {
if (err) {
return cb(err, null);
}
cb(null, results);
});
}
The callback convention is: cb(error, results...)
b) Use promises
DatabaseAccess.prototype.getWordPool = function () {
return RoundWord.find({}, 'words decoys', function (err, results) {
if (err) {
throw err; // however you might want to sanitize it
}
return results;
});
}
To consume this result you will need to do it as a promise
databaseAccess.getWordPool()
.catch(function (err) {
// process the error here
})
.then(function (results) {
// something with results
});
It will work if you change to this:
var dbAccess = require('../dao/dbAccess');
dbaInstance = new dbAccess();
dbaInstance.getWordPool(function(wordPool){console.log (wordPool);});
And:
var DatabaseAccess = function() {}
DatabaseAccess.prototype.getWordPool = function (cb) {
RoundWord.find({},'words decoys', function(err, wordPoolFromDB) {
if (err) throw err;
//console.log(wordPoolFromDB); -working ok
cb(wordPoolFromDB);
});
}
module.exports = DatabaseAccess;
If the function is Asynchronous you need to pass a callback to find to get the result:
DatabaseAccess.prototype.getWordPool = function (callback) {
RoundWord.find({},'words decoys', function(err, wordPoolFromDB) {
if (err) throw err;
callback(err, wordPoolFromDB);
});
}
and call it as follows in main:
dbaInstance.getWordPool(function (err, wordPool) {
console.log (wordPool);
// wordPool is only available inside this scope,
//unless assigned to another external variable
});
// cannot access wordPool here
I'm going to the next step of my webscraper today !
I'm already looping on an url array with async and I would loop again in this callback and wait for its exectution before restart.
I can not figure out how use two callback.
This is my code :
var getWebData = function(url) {
var data = [];
async.eachSeries(url, function(urlSingle, cb) {
request(urlSingle, function(err, resp, body) {
if (!err) {
var $ = cheerio.load(body);
var categoriesURL = [];
$('.ombre_menu li').each(function(i, element) {
$(this).find('.nav_sous-menu_bloc li a').each(function(i, element) {
categoriesURL.push('https://blabla' + $(this).attr('href'));
})
// I WANT TO LOOP on the categoriesURL array HERE
var jsObject = { name : "", description : "", price: "", categorie: "", liter: "", kilo: "", pricePer: "", quantity: "", capacity: "", promotion: "", scrapingDate : "", url: "" };
data.push(jsObject);
})
}
cb();
})
}, function() {
// this will rum when loop is done
var json = JSON.stringify(data);
fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err) {
console.log('File successfully written!');
});
});
}
getWebData(url);
app.listen('8080');
Does anyone know how can I do ?
Thanks
Made couple of changes in your code:
Used .mapSeries in place of .eachSeries. This way you can get data from iterator function in same order as the input array. Means you'll get [4,9] for input [2,3] to a square function, never [9,4]
Broke code into functions so that each function does one specific task
Moved categoriesURL processing out of loop 1
Returning early. It improves code readability. if (err) return callback(err);
function getWebData(url) {
// Using .mapSeries in place of .eachSeries as you seem to want to get data from iterator function
async.mapSeries(url, processUrl, function(err, results) {
// this will rum when loop is done
var json = JSON.stringify(results);
fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err) {
console.error('Error', err);
console.log('File successfully written!');
});
});
}
function processUrl(url, callback) {
request(url, function(err, resp, body) {
if (err) // Return simple cases early; Improves code readability
return callback(err); // or return callback(); -- if you don't want to send error upwards
var $ = cheerio.load(body);
var categoriesURL = [];
$('.ombre_menu li')
.each(function(i, element) { // loop 1
$(this)
.find('.nav_sous-menu_bloc li a')
.each(function(i, element) { // loop 2
categoriesURL.push('https://blablablac' + $(this)
.attr('href'));
}) // loop 2 end
}) // loop 1 end
// I WANT TO LOOP ON THE categoriesURL ARRAY HERE
// Using .mapSeries in place of .eachSeries for same above reason
async.mapSeries(categoriesURL, processCategoryUrl, function(err, results) {
if (err)
return callback(err);
// This function is called after process array categoriesURL
// Do what you want here then call callback provided to this method
return callback(null, results);
})
})
}
function processCategoryUrl(categoryUrl, callback) {
// Just process categoryUrl here and call callback with error or results
return callback();
}
getWebData(url);
app.listen('8080');
You can use nested eachSeries. Like this:
var getWebData = function(url) {
var data = [];
async.eachSeries(url, function(urlSingle, cb) {
request(urlSingle, function(err, resp, body) {
if (!err) {
var $ = cheerio.load(body);
var categoriesURL = [];
$('.ombre_menu li').each(function(i, element) {
$(this).find('.nav_sous-menu_bloc li a').each(function(i, element) {
categoriesURL.push('https://blablablac' + $(this).attr('href'));
})
async.eachSeries(caturl, function(categoriesURL, cb2) {
//Do whatever you want to do here
cb2();
}, function() {
//You can apply if and else for err an according to that you can set your callback responce here
cb();
};
})
}
})
}, function() {
// this will rum when loop is done
var json = JSON.stringify(data);
fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err) {
console.log('File successfully written!');
});
});
}
getWebData(url);
app.listen('8080');
i am stacking on this problem since a week, it's a problem of synchronize on Node JS.
The process that I want to do is :
1- check the existence of table (collection). --> if not insertion of data
2- if the table was created, then i have to find all data on table and compare it with the data that i want to insert.
3- if the new data is already exist on the database (table) the program doesn't do any thing, if not the program inserts the new data to the the database (table).
So we have 3 functions should be scheduled.
function 1
var getCollection = function(collection, new_theme, nbr_indicateur,callback) {
dbObject.listCollections().toArray(function(err, collections){
if ( err ) throw err;
assert.equal(err, null);
collections.forEach(function(collect){
if(collect.name == collection)
{
callback(true);
}
else {
dbObject.collection(collection).insertOne( {
"name_theme" : new_theme,
"nbr_indicateur" : nbr_indicateur
}, function(err, result) {
assert.equal(err, null);
console.log("Inserted a document into the Table_Mapping_Theme collection.");
});
callback(false);
}
});
});
};
function 2 :
var getData = function(value, collection, theme, callback) {
var clb = true;
if(value)
{
dbObject.collection(collection).find({}).toArray(function(err, docs){
if ( err ) throw err;
assert.equal(err, null);
docs.forEach(function(doc){
if(doc.name_theme == theme)
{
console.log("ce theme existe déja");
clb = false;
}
});
});
}
callback(clb);
};
function 3 :
var insertData = function(value, collection, new_theme, nbr_indicateur, callback) {
if(value)
{
dbObject.collection(collection).insertOne( {
"name_theme" : new_theme,
"nbr_indicateur" : nbr_indicateur
}, function(err, result) {
assert.equal(err, null);
console.log("Inserted a document into the "+collection+" collection.");
});
}
callback("done");
};
calling those functions (app.post using express js)
here i tried with pyramid method but it doesn't work
app.post('/setting/add_theme', urlencodedParser, function(req, res) {
getCollection('Table_Theme', req.body.new_theme, req.body.nbr_indicateur, function(value0){ console.log("0"+value0);
getData(value0,'Table_Theme', req.body.new_theme, function(value1) { console.log("1"+value1);
insertData(value1, 'Table_Theme', req.body.new_theme, req.body.nbr_indicateur, function(value2){ console.log("2"+value2);
});
});
});
res.redirect('/setting');
});
I am creating a service in sails js. I want to update the value of totalCount before returning it. But the problem is when the return is in the callback of the async.series I am getting an undefined when I'm invoking it. How should I do this?
var totalCount = 0;
async.series([
function getProducts(cb_series){
Inventory.find({sku_id : sku_id, bay_id : bay_id})
.then(function(inventory_items){
async.each(inventory_items, function(item, cb_each){
totalCount = totalCount + item.physical_count;
cb_each();
}, function(err){
if(err)
console.log(err);
cb_series();
});
});
}
], function returnResult(err, cb){
if(err)
console.log(err);
return totalCount;
});
I'm not totally sure what you're trying to do. But you probably want to pass totalCount out in a callback like this:
function getProducts(callback){
Inventory.find({sku_id : sku_id, bay_id : bay_id}).then(
function(inventory_items){
callback(null, inventory_items.length)
}, function(err){
console.log(err);
callback(err);
});
}
If there is an error, it will call back with the error as it's first parameter, so do a null check on that. If the first parameter is null, then the second parameter will be the length of your array.
If you'd rather return all of the products and not just the length (as the name of the function implies), then it's very similar:
function getProducts(callback){
Inventory.find({sku_id : sku_id, bay_id : bay_id}).then(
function(inventory_items){
callback(null, inventory_items)
}, function(err){
console.log(err);
callback(err);
});
}
You'd use it like this for the first case:
getProducts(function(err, productCount) {
if(err) {
console.log(err);
return err;
} else {
var totalCount = productCount;
}
//etc etc...
}
...or this for the second case:
getProducts(function(err,products) {
if(err) {
console.log(err);
return err;
} else {
var productArray = products;
}
//etc etc...
}
In "view" method within my controller was previously using node-async but I wanted to try out using q.
I'm currently trying to convert this
exports.view = function (req, res) {
var category = req.params.category,
id = req.params.id,
ip = req.connection.remoteAddress,
slug = req.params.slug,
submission,
userId = typeof req.session.user !== 'undefined' && req.session.user.id ? req.session.user.id : null,
views;
var getSubmission = function (submissionId, callback) {
Submission.getSubmission({
id: submissionId
}, function (err, submission) {
if (err) {
callback(err);
} else if (submission) {
callback(null, submission);
} else {
callback(err);
}
});
};
async.waterfall([
function (callback) {
getSubmission(id, callback);
},
function (submission, callback) {
res.render('submission', {
title: submission.title + ' -',
submission: submission
});
}]);
To using q... I started doing something like:
var getSubmission = function(id) {
return Submission.getSubmission({
id : submissionId
}).then(function(submission) {
return submission;
});
};
q.fcall(getSubmission).then(function(submission) {
console.log(submission);
});
But it's not quite working as I intended. Am I doing something wrong here? How can I do this?
Is Submission.getSubmission a call to a database? Then you can't "chain" promises to that. You'll have to use the deferred method:
var getSubmission = function(id) {
var deferred = Q.defer();
Submission.getSubmission({
id: id
}, function(err, data){
if (err) {
deferred.reject(err);
} else {
deferred.resolve(data);
}
});
return deferred.promise;
}
getSubmission(some_id).then(successCallback, failureCallback);
You can also use Q#denodeify to convert a function using nodejs-style callbacks (function(err, data)) into a promise based function. Thus, the above can also be achieved by the following:
getSubmissionPromise = Q.denodeify(Submission.getSubmission);
getSubmissionPromise({id: some_id}).then(successCallback, failureCallback);