I have a list of 80 items and I get 10 item on each page.Now my idea is to write all the data into file in such a way that first 10 will be in one file and then next 10 in another and so on i get 8 pages for my 80 blogs of 10 in each page.The problem is I am getting only one file got written with 10 blogs what about the else.Can anyone please find the error.Thanks.For that I wrote the script as follows,
I find that the loop is not getting incremented.
exports.getBlogsTest = function(req, res) {
helper.logs('getBlogs', 'blog');
var pages = ['undefined', '2', '3', '4', '5', '6', '7', '8'],
pageNum = '';
pages.forEach(function(i, v) {
try {
var currentPage = Number(i);
var itemsPerPage = 10;
var startItem = (currentPage - 1) * itemsPerPage;
async.waterfall([
function(done) {
try {
if (currentPage === 1) {
blogs.count().exec(function(err, count) {
if (err) {
helper.logs('getBlogs', 'blog', err, 'console');
throw err;
} else {
done(err, count);
}
});
} else {
done('', 'page');
}
} catch (e) {
helper.logs('getBlogs', 'blog', e.message);
}
},
function(count, done) {
try {
if (count) {
if (count && count !== 'page') {
res.setHeader('totalItems', count);
}
blogs.find().sort({ date: -1 }).select('-text').skip(startItem).limit(itemsPerPage).exec(function(err, data) {
if (err) {
helper.logs('getBlogs', 'blog', err, 'console');
throw err;
}
if (data && data.length > 0) {
res.send(data);
console.log('reached###################')
if (i === 'undefined') {
pageNum = '';
} else {
pageNum = i;
}
var fileName = 'public/amp/test2/amp-blog-list' + pageNum + '.html';
var modData = data;
fs.writeFile(fileName, modData, function(err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
} else {
res.send([]);
}
});
} else {
res.send([]);
}
} catch (e) {
helper.logs('getBlogs', 'blog', e.message);
}
}
],
function(err) {
helper.logs('getBlogs', 'blog', err, 'console');
throw err;
});
} catch (e) {
helper.logs('getBlogs', 'blog', e.message);
}
})
};
Why are you using so many try catch?
While it might be useful in many cases you should avoid using it when not necessary.
A few points where you had an issues:
var currentPage = Number(i);
when i is 'undefined' currentPage === NaN
same for var startItem = (currentPage - 1) * itemsPerPage;
when currentPage is 'NaN' startItem === NaN
What i guess is that you thought the params in forEach are (index, value) but it's the other way round (value, index)
I tried to improve your code a bit but haven't actualy run it.
exports.getBlogsTest = function(req, res) {
helper.logs('getBlogs', 'blog');
var itemsPerPage = 10;
for (var i = 1; i < 11; i++) { // pages 1-10
(function(currentPage){ // currentPage = i
var startItem = (currentPage - 1) * itemsPerPage;
async.waterfall([
function(done) {
if (currentPage === 1) {
blogs.count().exec(function(err, count) {
if (err) {
helper.logs('getBlogs', 'blog', err, 'console');
//throw err;
done(err); // the done callback will be called with the error
} else {
done(null, count); // no error so send null
}
});
} else {
done(null, 'page'); // no error so send null
}
},
function(count, done) {
if (count) {
if (count !== 'page') {
res.setHeader('totalItems', count);
}
blogs.find().sort({ date: -1 }).select('-text').skip(startItem).limit(itemsPerPage).exec(function(err, data) {
if (err) {
helper.logs('getBlogs', 'blog', err, 'console');
done(err); // you never called done
//throw err;
}
if (data && data.length > 0) {
res.send(data);
var fileName = 'public/amp/test2/amp-blog-list' + (currentPage === 1 ? '' : currentPage) + '.html';
var modData = data;
fs.writeFile(fileName, modData, function(err) {
if (err) {
done(err);
return console.log(err);
}
console.log("The file was saved!");
done(); // you never called done
});
} else {
res.send([]);
done(); // you never called done
}
});
} else {
res.send([]);
done(); // you never called done
}
}
], function done(err) {
// this is called when waterfall is done or in case of error
// it would always throw if you didn't check for error
// also is it necessary to throw?
// if (err) throw err;
helper.logs('getBlogs', 'blog', err, 'console');
});
})(i);
}
};
Related
I'm trying to get the url for each element, but when it goes to my MODEL query it stays in the first element of the array. Any ideas to solve this?
var loopAndInsert = function(myData) {
for (var i = 0; i < myData.length; i++) {
var prop = myData[i];
MODEL('myModel').query(prop.url, (err, res) => {
if (err) callback(err);
if (res[0].url) {
console.log(res[0].url);
return
} else {
MODEL('myModel').insert(prop, (err, res) => {
if (err) throw err;
else {
console.log('done');
}
});
}
});
}
}
var loopAndInsert = function(myData) {
for (var i = 0; i < myData.length; i++) {
let prop = myData[i];
MODEL('myModel').query({url: prop.url}, (err, res) => {
if (err) callback(err);
if (res.length !== 0) {
console.log('not added already in system');
return
} else {
MODEL('myModel').insert(prop, (err, res) => {
if (err) throw err;
else {
console.log('in db');
}
});
}
});
}
}
I am trying to update object values inside of array. I have done the method and search the element in the array that I want, and returns me 200. But after when I do another request the value return to the original (is not saving).
First of all this is the schema:
{
"_id" : "1",
"username" : "a",
"elements" : [{"_id": "22", "name":"bb"}, {"_id":"33", "name": "cc"}]
}
and this is my method
update = function(req, res) {
User.findById(req.params.id, function (err, user) {
if (!user) {
res.send(404, 'User not found');
}
else{
var array = user.elements;
for (var i = 0; i < array.length; i++) {
if (array[i]._id == "22") {
result = array[i];
if (req.body.name != null) result.name = req.body.name;
result.save(function(err) {
if(!err) {
console.log('Updated');
}
else {
console.log('ERROR: ' + err);
}
res.send(result);
});
break;
}
}
}
});
}
I don't know what I am doing wrong. I mean I simplified everything but I think that the problem is in the method.
You have to save the user object and result just like this :
update = function(req, res) {
User.findById(req.params.id, function (err, user) {
if (!user) {
res.send(404, 'User not found');
}
else{
var array = user.elements;
for (var i = 0; i < array.length; i++) {
if (array[i]._id == "22") {
result = array[i];
if (req.body.name != null) result.name = req.body.name;
break;
}
}
user.save(function(err) {
if(!err) {
console.log('Updated');
}
else {
console.log('ERROR: ' + err);
}
res.send(user);
});
}
});
}
I'm trying to rewrite a retry function with callbacks into a Bluebird promise one but can't seem to get my head around the correct way of doing this. At the bottom is the working callback function for retrying Azure DocumentDB when limit is met. I'm trying to use promises in the function itself but it returns before reaching the "Then". Any hints on how to tackle this or if performance is affected by using catch this way would be appreciated. Thank you!
"readDocRetry": function(id, retries) {
var self = this;
return new Promise(function(resolve, reject){
self.client.readDocumentAsync(self.docsLink + id, null, function(err, data){
if (err) {
reject(err);
} else {
resolve(data)
}
}).then(function(results) {
console.log("ReadDocRetry result: " + results)
return results;
}).catch(function(err, headers) {
RetryError(self, id, err, headers, retries);
});
});
}
function RetryError(self, id, err, headers, retries) {
if (err && err.code) {
if (err.code === 429 && retries >= 0) {
setTimeout(function() {
self.readDocRetry(id, retries - 1);
}, Number(headers['x-ms-retry-after-ms'] || 1));
}
else if (err.code === 503 && retries >= 0) {
setTimeout(function() {
self.readDocRetry(id, retries - 1)
}, 500);
}
}
else if(err) {
console.log(err);
}else{
console.log("Err missing in RetryError");
}
}
bbCtx.readDocRetry("19").then(function(res){
console.log("Hurrah!" + res);
})
------- Working example with traditional callbacks which I'm trying to make promise based -----
dbContext.prototype = {
readDocRetry: function (id, retries, cb) {
var self = this;
self.client.readDocument(self.docsLink + id, function (err, results, headers) {
if (err) {
if (err.code === 429 && retries >= 0) {
var aR = retries - 1;
setTimeout(function () {
self.readDocRetry(id, aR, cb);
}, Number(headers['x-ms-retry-after-ms'] || 1));
} else if (err && err.code === 503 && retries >= 0) {
var aR = retries - 1;
setTimeout(function () {
self.readDocRetry(id, aR, cb)
}, 500);
} else {
cb(err);
}
} else {
cb(null, results);
}
});
},
When your catch callback is supposed to handle anything, it will need to return that new result like every other promise callback. In your case, it could return the promise for the result of the retry attempt:
function readDocRetry(id, retries) {
var self = this;
return new Promise(function(resolve, reject){
self.client.readDocumentAsync(self.docsLink + id, null, function(err, data){
if (err) {
reject(err);
} else {
resolve(data)
}
});
}).then(function(results) {
console.log("ReadDocRetry result: " + results)
return results;
}).catch(function(err, headers) {
if (err && err.code) {
if (err.code === 429 && retries >= 0) {
return Promise.delay(headers['x-ms-retry-after-ms'] || 1).then(function() {
return self.readDocRetry(id, retries - 1);
});
} else if (err.code === 503 && retries >= 0) {
return Promise.delay(500).then(function() {
return self.readDocRetry(id, retries - 1)
});
}
}
if (err) {
console.log(err);
throw err;
} else {
console.log("Err missing in RetryError");
throw new Error("rejection without error");
}
});
}
I am a node.js noob and am trying to do some file processing. I'm using async to process an array of files but the callback function is never called. I believe this is due to calling the next() function twice but I can't see where I'm doing this. If I comment out the last "return next()" I finish with no errors but the final callback doesn't execute. If I uncomment out this line I get the error message "callback was already called". Any help would be greatly appreciated. Here is the code:
/*jslint node: true */
"use strict";
var fs = require('fs'),
dive = require('dive'),
subdirs = require('subdirs'),
async = require('async'),
currentYear = new Date().getFullYear(),
cpFile = __dirname + "/" + "header.txt",
noCopy = __dirname + "/" + "noCopyright.txt",
currentHeads = __dirname + "/" + "currentHeaders.txt",
reYear = /\s(\d{4})[-\s]/i, // matches first 4 digit year
reComment = /(\/\*(?:(?!\*\/).|[\n\r])*\*\/)/, // matches first multi-line comment
allHeaders = {},
stringObj,
year,
top;
function needsHeader (file) {
if ((file.match(/.*\.js$/) || file.match(/.*\.less$/) || file.match(/.*\.groovy$/) || file.match(/.*\.java$/) || file.match(/.*\.template$/) || file.match(/.*\.html$/))) {
fs.appendFile(noCopy, file + "\n", function (err) {
if (err) {
return console.log(err);
}
});
}
}
fs.readFile(cpFile, 'utf8', function (err, copyRight) {
if (err) {
return console.log(err);
}
subdirs(__dirname, 4, function (err, dirs) {
if (err) {
return console.log(err);
}
async.each(dirs, function (dir, next) {
if (! dir.match(/.*\/src$/)) {
return next();
} else {
dive(dir, {all: false}, function (err, file) {
if (err) {
return next(err);
} else {
fs.readFile(file, 'utf8', function (err, data) {
if (err) {
return next(err);
} else {
if (data.match(reComment) && (file.match(/.*\.js$/) || file.match(/.*\.less$/) || file.match(/.*\.groovy$/) || file.match(/.*\.java$/) || file.match(/.*\.template$/))) {
top = data.match(reComment)[0];
if (top.match(reYear)) {
year = top.match(reYear)[1];
if (allHeaders[year]) {
allHeaders[year].push(file);
} else {
allHeaders[year] = [file];
}
} else {
needsHeader(file);
}
} else {
needsHeader(file);
}
return next();
}
});
}
});
}
}, function (err) {
if (err) {
console.log(err);
}
stringObj = JSON.stringify(allHeaders, null, 4);
fs.writeFile(currentHeads, stringObj, function (err) {
if (err) {
return console.log(err);
}
});
});
});
});
It expects you to call next() for each directory, and you are calling it for each file found in the directory. So as soon as some directory contains 2 or more files, you get the error.
To fix it, try call next() on dive complete. See the dive documentation:
complete [optional] may define a second callback, that is called,
when all files have been processed. It takes no arguments.
dive(dir, {all: false}, function (err, file) {
if (err) {
return next(err);
} else {
// your file handling code here
}
}, function complete() {
next();
});
Hi I am trying to use the Async module to retrieve two users and do some processing after they have both been retrieved however I keep getting the error message: Callback was already called. Below is the code i currently have:
app.get('/api/addfriend/:id/:email', function(req, res) {
var id = req.params.id;
var friendEmail = req.params.email;
async.parallel([
//get account
function(callback) {
accountsDB.find({
'_id': ObjectId(id)
}, function(err, account) {
console.log(id);
if (err || account.length === 0) {
callback(err);
}
console.log(account[0]);
callback(null, account[0]);
});
},
//get friend
function(callback) {
accountsDB.find({
'email': friendEmail
}, function(err, friend) {
console.log(friendEmail);
if (err || friend.length === 0 || friend[0].resId === undefined) {
callback(err);
}
console.log(friend[0]);
callback(null, friend[0].resId);
});
}
],
//Compute all results
function(err, results) {
if (err) {
console.log(err);
return res.send(400);
}
if (results === null || results[0] === null || results[1] === null) {
return res.send(400);
}
//results contains [sheets, Friends, Expenses]
var account = results[0];
var friend = results[1];
if (account.friends_list !== undefined) {
account.friends_list = account.friends_list + ',' + friend;
}
else {
account.friends_list = friend;
}
// sheetData.friends = results[1];
accountsDB.save(
account,
function(err, saved) {
if (err || !saved) {
console.log("Record not saved");
}
else {
console.log("Record saved");
return res.send(200, "friend added");
}
}
);
}
);
});
Any help would be appreciated.
Add else statement to your code, because if you get error, your callback executes twice
if (err || account.length === 0) {
callback(err);
} else {
callback(null, account[0]);
}
The docs from async actually say:
Make sure to always return when calling a callback early, otherwise
you will cause multiple callbacks and unpredictable behavior in many
cases.
So you can do:
return callback(err);