Within a function that is already within Meteor.binEnvironment, when I run <collection>.find ({}), I get the error throw new Error ('Can \' t wait without a fiber ');
If you place that call also within Meteor.bindEnvironment(<collection>.find ({})), the error message becomes: throw new Error (noFiberMessage);
The function in question runs through Meteor.methods ({})
Where am I going wrong?
Example to reproduce the error:
Meteor.methods({
"teste" : Meteor.bindEnvironment(function(){
var Future = Meteor.require('fibers/future');
var future = new Future();
setTimeout(function(){
return future.return(Sessions.findOne({}))
}, 15000);
console.log('fut', future.wait());
})
});
Try using Meteor._wrapAsync instead.
This is an example of an async function, but any other would do:
var asyncfunction = function(callback) {
Meteor.setTimeout(function(){
callback(null, Sessions.findOne({}))
}, 15000);
}
var syncfunction = Meteor._wrapAsync(asyncfunction);
var result = syncfunction();
console.log(result);
You could wrap any asynchronous function and make it synchronous and bind the fibers with it this way.
I could not apply the suggested solution in my project, currently do this way:
Meteor.methods({
"teste" : Meteor.bindEnvironment(function(){
var Fiber = Meteor.require('fibers');
var Future = Meteor.require('fibers/future');
var future = new Future();
setTimeout(function(){
return future.return(
Fiber(function(){
Sessions.findOne({});
}).run()
);
}, 15000);
console.log('fut', future.wait());
})
});
Related
I am using firebase and in below query extand() is a function that concatenate the objects. Can some one help me to remove $timeout from my query ?
currently i am waiting for my playerList to fill.
var getJoinedPlayers = function(gameId){
var deferred = $q.defer();
var playerList = {};
var usersRef = new Firebase(FBURL+'users');
var gameRef = new Firebase(self.firebaseURL);
var gamePlayersRef = gameRef.child(gameId).child("players");
gamePlayersRef.on("child_added", function(snap) {
usersRef.child(snap.key()).once("value", function(data) {
playerList[snap.key()] = extend({'playerId': snap.key()},data.val());
})
});
$timeout(function() {
if (playerList) {
deferred.resolve(playerList);
} else {
reason = {'message': "player Not found"};
deferred.reject(reason);
}
}, 1300);
return deferred.promise;
};
I would simplify this by replacing "child_added" with "value". This will return the list of players, which you could iterate over with regular JS.
Then call
usersRef.child(snap.key()).once("value", function(data)
for each of of the items in the result, and push each of these promises into an array
promiseArray.push(usersRef.child(snap.key()).once("value", function(data)...
then you could
$q.all(promiseArray).then(...
that will combine all promises into a single promise
I am having trouble with getting return value from wrapAsync function in meteor. Below is my code
Template.greet.helpers({
greet : function () {
var convertAsyncToSync = Meteor.wrapAsync( HTTP.get );
resultOfAsyncToSync = convertAsyncToSync('http://www.demo.com/api/greet', {} );
console.log(resultOfAsyncToSync);
return resultOfAsyncToSync;
}
});
I get undefined value in console.
try
Template.greet.onCreated(function(){
this.apiResult = new ReactiveVar(null);
})
Template.greet.helpers({
greet : function () {
var t = Template.instance();
HTTP.get('http://www.demo.com/api/greet', {}, function(e,r){
//process response and save it in reactivevar
t.apiResult.set(r.data);
});
return t.apiResult.get();
}
});
don't forget to add package meteor add reactive-var
EDIT
Template.greet.onRendered(function(){
var t = Template.instance();
HTTP.get('http://www.demo.com/api/greet', {}, function(e,r){
//process response and save it in reactivevar
t.apiResult.set(r.data);
});
})
Template.greet.helpers({
greet : function () {
var t = Template.instance();
return t.apiResult.get();
}
});
This is weird but when I call a external function from Meteor.method function it will always return undefined in the client I tried Meteor.wrapAsync but I think I'm doing something wrong. Here is my code:
var demoFunction = function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
Meteor.methods({
// NOT WORKING, How can I make this work?
methodDemo: function () {
var result = demoFunction ();
return result;
},
// Works
methodDemo2: function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
});
// Call from client
Meteor.call("methodDemo", function (err, res) { });
calling external functions doesn't work the same way if I put the code inside the meteor method why?
Try using Meteor.userId() in your function instead of this.userId. I think you are loosing the value of this when calling your function causing it to exit early.
Since you declared the function with a var it is scoped outside of methodDemo().
You could declare the function globally by removing var or move the demoFunction() code into methodDemo().
I have to make a aggregate query to DB when the user click on a button, however I don't know how to return that result back to the client since I'm doing an asynchronous request, this is part of my code:
//Server side
Meteor.startup(function() {
Meteor.methods({
getAllTotals: function (query){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var error = result = match = pipeline = '';
var group = {
$group: {
_id: null,
wall_clock: {
"$sum": "$wall_clock"
},
mem:{
"$sum": "$mem"
},
cpu:{
"$sum": "$cpu"
},
io:{
"$sum": "$io"
},
vmem:{
"$sum": "$vmem"
},
maxvmem:{
"$sum": "maxvmem"
}
}
};
if(typeof query.submission_time !== "undefined"){
match = {"$match": {submission_time: query.submission_time}};
pipeline = [match, group];
}else{
pipeline = [group];
}
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
console.log(result); // <<--- this is OK!
},
function(error) {
Meteor._debug( "Error doing aggregation: " + error);
}
)
);
return result; // <<--- this is empty
}
});
}
any suggestion? :-)
Short answer:
Solution you can find here:
How to get an async data in a function with Meteor
Detailed answer
using Meteor._wrapAsync
var aggregateTotal = function(callback){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
function (error, result){
if(error){
callback(error);
}else{
callback(null, result);
}
}
);
}
var aggregateTotalsSync = Meteor._wrapAsync(aggregateTotal);
Meteor.methods({
'getAllTotals': function(){
var result;
try{
result = aggregateTotalsSync();
}catch(e){
console.log("getAllTotals method returned error : " + e);
}finally{
return result;
}
}
});
using Futures (meteorPad example)
//Server side
Meteor.startup(function() {
var Future = Npm.require('fibers/future');
Meteor.methods({
getAllTotals: function (query){
var fut = new Future();
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
if(error){
fut.throw(error);
}else{
fut.return(result)
}
},
function (exception){
// caught exception is passed to this callback
fut.throw(exception);
}
)
);
return fut.wait();
}
});
}
Easy but a bit dirty way (but not so much if you think well about your architecture) -> send back the result trough Mongo.
You can even do it without Meteor.methods, with the request creation inserted in the database on the client, an observer on the server that check it and does the async task, and then write back the result in the database.
I'm trying to simply return what I request in PHP to JSON.
My problem is that each Stock is not yet completed.
Indeed, it is the "render" but "this.collection.models" is not yet completed because the request is not yet finished.
What should I do to correct this problem, wait until the request is finished so that the loop is done correctly.
Thank you in advance
var Article = Backbone.Model.extend({});
var Articles = Backbone.Collection.extend({
model:Article,
url: function() {
return _BASE_URL+'/sync/getLastArticles';
},
initialize:function () {
this.fetch();
}
});
var ArticlesView = Backbone.View.extend({
template:$('#articles').html(),
initialize:function () {
this.collection = new Articles();
this.render();
},
render:function () {
console.log(this.collection);
var that = this;
_.each(this.collection.models, function (item) {
console.log(item);
}, this);
},
renderArticle:function () {
;
}
});
You render before the fetch is done. What you want to do, is to wait for the fetch to complete and then render. Now how would you get notification of when the fetch is done? You have 2 options:
The success function (Not recommended by me)
// ArticlesView
initialize: function() {
_.bindAll(this); // Don't forget to BIND
this.collection = new Articles();
this.collection.fetch({
success: this.render
});
}
Now when the fetch has been successful, render is called. This however can cause scoping problems and Backbone.js offers a much nicer alternative to callback functions: events.
Event callback (prefer this)
// ArticlesView
initialize: function() {
_.bindAll(this);
this.collection = new Articles();
this.collection.on('reset', this.render); // bind the reset event to render
this.collection.fetch();
}