Handling async database in nodejs - javascript

I'm new in node js. I'm using sails js as framework. I'm trying to use nested database query.
Please check the added code.
My current mongo collection name is todostatus. Form it i grabbed the data . Then I tried to use a callback function to iterate the data and update each item inside the data from database. But I'm not getting all the data. Can anyone please give me lead?
Thanks in advance,
Nixon
TodoStatus.find({todo_id : req.params.todo_id}).done(function(errs, responsible){
if(errs){
}
else{
function grabUsersName(todoRes, callback){
async.forEach(todoRes, function (item, callback2){
User.findOne ({id : item.user_id}).done(function (errses, user) {
if(errses)
{
console.log(errses);
}
else
{
item['name'] = user.name;
}
});
}, function(eerr) {
callback(todoRes);
});
}
grabUsersName(responsible, function(resultsa){
console.log(resultsa);
return res.view({
responsible: resultsa
})
})
}
})

I found the solution.
The issue is in the function grabUserName(). I missed to use callback for the async.forEach. Check the functions code for more information
function grabUsersName(todoRes, callback){
async.forEach(todoRes, function (item, callback2){
User.findOne ({id : item.user_id}).done(function (errses, user) {
if(errses){
console.log(errses);
}
else{
item['name'] = user.name;
callback2();
}
})
}, function(eerr) {
callback(todoRes);
});
}

Related

Mongodb, how to multiple request to aliment 1 object

i'm creating a forum, and i want to get the number of message in one topic,
so in my method GetListTopic i get the list of topic, and after i want to know how many message there is in one topic so i request the table forum_message for every topic in my list=>
db.Forum_Topic.count({}, function (err, topicount) { //nombre de topic
db.Forum_Topic.find().skip(skipNumber).limit(nombreDeTopicParPage).sort({ dateLastMessage: -1 }, function (err, dbres) {
//dbres = liste de topic
for (var i in dbres)
{
db.Forum_Message.count({ idTopic: new mongojs.ObjectID(dbres[i]._id) }, function (err, Messagecount) {
dbres[i].TotalMessage = Messagecount;
});
}
res.send([dbres, topicount]);
});
});
my need is to add in every object of my list the total message => dbres[i].TotalMessage = Messagecount;
but that don't work dbres[i].TotalMessage is set correctly in the function callback but when i send object TotalMessage doesn't exist ....
someone can help me please ?
The problem is that you are using for loop within an async function. And that res.send() statement does not wait for the loop to complete. It executes before.
There is a solution by using this async library. There are also many options in this library, however, I think the async.each() is the one you can try.
Good luck.
i finally found the solution to foreach update with nodejs and mongodb,
i use async.js here : https://www.npmjs.com/package/async
and to delete a liste of mail
async.each(ListeIdMailToDelete, function (mailID, callback) {
db.userMessageMail.find({ _id: db.ObjectId(mailID) }, function (err, dbres) {
if (dbres.length > 0)
{
if (dbres[0].expediteur == newplayer.pseudo || dbres[0].destinataire == newplayer.pseudo) {
db.userMessageMail.remove({ _id: dbres[0]._id }, function () {
callback(err);
})
}
}
});
}, function (err) {
console.log(err);
});

Meteor js | Display Json in view via helper

Im struggling with an issue using Meteor JS.
I call an api wich return me a Json array wich look like the one returned on this url (I don't put the whole array here cause of the size): https://blockchain.info/address/12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?format=json&offset=0
I call it server side like :
if (Meteor.isServer) {
Meteor.methods({
getWalletPreviousTx: function() {
var url = "https://blockchain.info/address/12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?format=json&offset=0";
var result = Meteor.http.get(url);
if(result.statusCode==200) {
var tx = JSON.parse(result.content);
return tx;
} else {
console.log("Response issue: ", result.statusCode);
var errorJson = JSON.parse(result.content);
throwError("Couldn't fetch wallet balance from Blockchain, try again later !");
}
}
});
}
And i retrieve it to my view via an helper in a specific template :
Template.wallet.helpers({
addrTxs: function () {
Meteor.call('getWalletPreviousTx', function(err, tx) {
console.log(tx);
return [tx];
});
}
});
The console.log in the helper actually log my Json array wich mean it have access to it.
Now the part im struggling with is to retrieve this Json to my view, i've tried a lot of way and none of them works, actually i have this in my view :
<template name="wallet">
<table>
{{#each addrTxs}}
<ul>
{{> addrTx}}
</ul>
{{/each }}
</table>
</template>
The part of the Json I want to display is the "addr" and "value" of each transactions :
"inputs":[
{
"sequence":4294967295,
"prev_out":{
"spent":true,
"tx_index":97744124,
"type":0,
"addr":"1AWAsn8rhT555RmbMDXXqzrCscPJ5is5ja",
"value":50000,
"n":0,
"script":"76a914683d704735fd591ba9f9aebef27c6ef00cbd857188ac"
}
}
]
Fact is, i never managed to display anything from this Json array in my view, even puting directly this in my view doesn't show anything :
{{addrTxs}}
What am I doing wrong ? Can anyone help with this ?
Thanks for reading.
----------------------- Edit ---------------------
I think the problem is more that my helper and template are loaded before the api call is finished (because the console.log appear in my console like 3seconds after my page is rendered). How can i make my helper wait until the api call is finished before rendering it in the view ? I use iron router.
I have tried to add a waitOn action on my route in order to wait until my api call is finished :
Router.route('/wallet', {
name: 'wallet',
template: 'wallet',
loadingTemplate: 'loading',
waitOn: function () {
Meteor.call('getWalletPreviousTx', function(error, result) {
if(!error) {
Ready.set(result)
}
});
return [
function () { return Ready.get(); }
];
},
action: function () {
if (this.ready())
this.render();
else
this.render('loading');
}
});
The above code with the waitOn action seems to work (i have no errors) but i don't know the way to display in my view the specific result from :
if(!error) {
Ready.set(result)
}
Transactions are contained in tx.txs, iterates through that.
Template.wallet.helpers({
addrTxs: function () {
Meteor.call('getWalletPreviousTx', function(err, tx) {
console.log(tx);
return tx.txs;
});
}
});
You're right, you need to use the sessions variables with async call.
First, call method on created :
Template.wallet.created = function () {
Meteor.call('getWalletPreviousTx', function(err, tx) {
console.log(tx.txs);
Session.set('tx', tx.txs);
});
};
Helper should look like this :
Template.wallet.helpers({
addrTxs: function () {
return Session.get('tx');
}
});

Grab attribute of current record for Meteor Method Call

I am working on a project to pull in twitter timeline's for selected teams/players. When I am on the team/_id page, how can I grab an attribute to path through a method?
Below is my client side javascript, as well as the relevant route from iron router. When I type in something like "patriots" to the "????" section, I get a result. I would like to do this dynamically, I currently have the twitter handles stored under the twitter attribute.
Template.tweets.helpers({
teams: function() {
return Teams.find();
},
});
Template.tweets.onRendered(function () {
var twitterHandle = "???";
Meteor.call('getTimeline', twitterHandle, function(err,results){
if (err) {
console.log("error", error);
};
console.log(results);
Session.set("twitter", JSON.parse(results.content));
})
return Session.get("twitter");
});
Router.route('/teams/:_id', {
name: 'teamView',
template: 'teamView',
data: function(){
var currentTeam = this.params._id;
return Teams.findOne({ _id: currentTeam });
var twitterHandle = this.params.twitter;
return Teams.findOne({twitter: twitterHandle});
}
});
<template name="tweets">
<h3>Tweets</h3>
<div class="container">
{{twitter}}
</div>
</template>
You should be able to access all information from the current route using the Router.current() object. In your case you can use Router.current().params._id to get the _id param:
var twitterHandle = Router.current().params._id;
Edits based on your comments below
I did not notice that you were calling the Teams.findOne function twice in your route's data function. Form the looks of it you're already storing the twitter handle in the Teams collection, so you merely need to access the data that's returned by the route.
Template.tweets.helpers({
twitterData: function() {
//return the data stored in the callback function of the Meteor method call in the onRendered event
return Session.get('twitter');
}
});
Template.tweets.onRendered(function () {
//clear any previously stored data making the call
Session.set('twitter', null);
//property of the team document returned by the data function in the route.
var twitterHandle = this.data.twitter;
Meteor.call('getTimeline', twitterHandle, function(err,results){
if (err) {
console.log("error", error);
} else {
Session.set("twitter", JSON.parse(results.content));
}
});
});
Router.route('/teams/:_id', {
name: 'teamView',
template: 'teamView',
data: function(){
var currentTeam = this.params._id;
return Teams.findOne({ _id: currentTeam });
}
});
<template name="tweets">
<h3>Tweets</h3>
<div class="container">
<!-- twitterData will be an object, so you'll need to figure out what properties to display and use dot notation//-->
{{twitterData}}
</div>
</template>

async.waterfall bind context

I am currently working on a web application with node.js and I can't figure a context problem with the library async.
Here is a example of code of my application :
notification.prototype.save = function (callback) {
async.parallel([
// Save the notification and associate it with the doodle
function _saveNotification (done) {
var query = 'INSERT INTO notification (notification_id, user_id, doodle_id, schedule_id) values (?, ?, ?, ?)';
notification.db.execute(query, [ this.notification_id, this.user_id, this.doodle_id, this.schedule_id ], { prepare : true }, function (err) {
return done(err);
});
console.log("SAVE NOTIFICATION");
console.log("doodle_id", this.doodle_id);
}.bind(this),
// Save notification for the users with the good profile configuration
function _saveNotificationForUsers (done) {
this.saveNotificationForUsers(done);
}.bind(this)
], function (err) {
return callback(err);
});
};
So in this code, I have to use the bind method to bind the context of my object ( this ) because otherwise async change it. I got it.
But what I don't understand is why the code of this.saveNotificationForUsers does not work the same way :
notification.prototype.saveNotificationForUsers = function (callback) {
console.log("SAVE NOTIFICATION FOR USERS");
console.log("doodle id : ", this.doodle_id);
async.waterfall([
// Get the users of the doodle
function _getDoodleUsers (finish) {
var query = 'SELECT user_id FROM users_by_doodle WHERE doodle_id = ?';
notification.db.execute(query, [ this.doodle_id ], { prepare : true }, function (err, result){
if (err || result.rows.length === 0) {
return finish(err);
}
console.log("GET DOODLE USERS");
console.log("doodle id : ", this.doodle_id);
return finish(err, result.rows);
});
}.bind(this)
], function (err) {
return callback(err);
});
};
When I call the previous code, the first console.log is able to show me the "this.doodle_id" variable, which means the function knows the "this" context.
But the functions inside the waterfall call does not, even if I bind 'this' to them.
I figured a way to make it works by creating a 'me' variable which is equal to 'this' juste before I call waterfall, and by binding the functions with the 'me' variable' and not this, but I would like to understand why I am forced to do this when I use async.waterfall and not when I use async.parallel.
I hope I was clear with the description of my problem, if someone can help me understand it will be a great pleasure !
The problem you’re seeing has got nothing to do with parallel or waterfall but rather how in the waterfall case, you’re referencing this in the callback to notification.db.execute, whereas in the parallel case, there is only a call to done in there. You could use bind again to bind that callback as well:
async.waterfall([
function _getDoodleUsers (finish) {
//…
notification.db.execute(query, [ this.doodle_id ], { prepare : true }, function (err, result){
//…
}.bind(this)); // <- this line
}.bind(this)
], function (err) {
//…
});

AngularJS tutorial Thinkster.io chapter 7

UPDATE: The tutorial was updated and the following question really no longer applies
Learning about AngularJS from the site thinkster.io (free ebook). But at the moment i'm stuck at chapter 7 - Creating your own user data using firebase. This is an tutorial about angularjs that works with firebase.
I have wrote all the code according to the site, but i'm getting these console errors when I want to register a user. It will create the user (in firebase -simplelogin), but not the user object (in firebase - data).:
TypeError: undefined is not a function
at Object.User.create (http://localhost:9000/scripts/services/user.js:46:19)
at http://localhost:9000/scripts/controllers/auth.js:32:22
etc.
This is the code (same as the site), the error is in the create() function and talks about the users.$save() function, snippet of User.create():
users.$save(username).then(function () {
setCurrentUser(username);
});
Complete code of user.js:
news.factory("User", function ($firebase, FIREBASE_URL, $rootScope, $log) {
var reference, users, User;
reference = new Firebase(FIREBASE_URL + "users");
users = $firebase(reference);
function setCurrentUser(username) {
$rootScope.currentUser = User.findByUsername(username);
}
$rootScope.$on("$firebaseSimpleLogin:login", function (event, authUser) {
var query = $firebase(reference.startAt(authUser.uid).endAt(authUser.uid));
query.$on("loaded", function () {
setCurrentUser(query.$getIndex()[0]);
});
});
$rootScope.$on("$firebaseSimpleLogin:logout", function () {
delete $rootScope.currentUser;
});
User = {
create: function (authUser, username) {
users[username] = {
md5_hash: authUser.md5_hash,
username: username,
"$priority": authUser.uid
};
$log.debug(users);
users.$save(username).then(function () {
setCurrentUser(username);
});
},
findByUsername: function (username) {
if (username) {
return users.$child(username);
}
},
getCurrent: function () {
return $rootScope.currentUser;
},
signedIn: function () {
return $rootScope.currentUser !== undefined;
}
};
return User;
});
Edit 1:
Registering a user now works, got it working (saving in firebase, simple login and data):
users = $firebase(reference).$asObject();
Notice the users.save() function:
create: function (authUser, username) {
users[username] = {
md5_hash: authUser.md5_hash,
username: username,
$priority: authUser.uid
};
$log.debug(users);
users.$save().then(function () {
setCurrentUser(users);
});
},
findByUsername: function (users) {
if (users) {
return users;
}
},
Edit 2:
Now I get an error at the log in of the user (see below), when I want to log in, I get an error on this this function, query.$on():
TypeError: undefined is not a function
at http://localhost:9000/scripts/services/user.js:26:19
$rootScope.$on("$firebaseSimpleLogin:login", function (event, authUser) {
var query = $firebase(reference.startAt(authUser.uid).endAt(authUser.uid));
query.$on("loaded", function () {
setCurrentUser(query.$getIndex()[0]);
});
});
What is wrong now?
This is an answer on edit 2: I have used firebase(ref), query.$loaded and searched for the right object, that's it. Maybe someone have an different answer, please post them :).
I have finally completed chapter 07!
In general (solution for Edit 2):
$rootScope.$on("$firebaseSimpleLogin:login", function (event, authUser) {
var query = $firebase(reference).$asObject();
query.$loaded(function (result) {
angular.forEach(result, function (key) {
if (key.md5_hash === authUser.md5_hash) {
setCurrentUser(key);
}
});
});
});
This is not the ideal solution, but the free ebook (atm of writing) is far from ideal. Then again, these kind of situations helps you to understand a little bit more about the firebase api and how it works with angular. But can be frustrated at times, when you just want to go through the tutorial ;).
Note! I have saved the User object and pass the User object to the findUsername() and setCurrentUser() functions instead of just the user.username.
You can also use the native array function, like some().
I think your system uses the newer version of Angularfire (version>= 0.8). Which means for running through loops that are arrays ...you need to attach .$asArray() at the end of the user definition field. Check the updates of Firebase.

Categories

Resources