using Future.wait() in Meteor.methods - meteor

Running subscriptions in async mode with new Future() works fine but if the same thing is done in a Meteor.method the application crashes with a message that it can not wait without a fiber. But I have to return something from the Meteor.method
This is the method:
/**global variables*/
var Fiber = Npm.require("fibers");
var Future = Npm.require("fibers/future");
Meteor.methods({
'single-data': function (form, state, tenant, selectedRow, search, sort) {
var user = Meteor.users.findOne({_id: this.userId});
/**check if the user can see the data in the state*/
if (!(isAdmin(user, form) || hasPermission(user, form, state, "read"))) {
return null;
}
/** set the sort order for the query*/
var order = [];
if (sort) {
order.push(["fieldData." + sort.column + ".0.value", sort.order == 1 ? "asc" : "desc"]);
}
order.push(["submitTime", "desc"]);
var query = dataQuery(form, state, _.uniq(_.pluck(user.groups, "tenant")), search);
var fut = new Future();
var fut = new Future(); setTimeout(function () {
fut.ret(FormDatas.find(query, {sort: order, skip: selectedRow, limit: 1}).fetch()[0]);
}, 0 * 1000);
// Wait for async to finish before returning the result
return fut.wait();
}
});

I believe that the return value from future should not contain asynchronous code, it should happen before calling ret(). Anyway, in your case future is not needed, simply call
return FormDatas.findOne(query, options);

Related

How to call yield in firebase read API

I have a redux saga API, where by I am connecting to firebase and reading records of data.
var roomRef = firebase.database().ref('/Users/' + userid + '/rooms')
var rooms = []
roomRef.once('value', function (snap) {
var roomkeys = snap.val()
for (var roomkey in roomkeys) {
firebase.database().ref('/Rooms/' + roomkey).once('value', function (item) {
rooms.push(item.val())
})
}
console.log(rooms)
--> put({type: 'LOAD_ROOMS', payload: { rooms: rooms}})
})
Since my put is inside a callback function I cannot use the yield keyword. How do I dispatch an event to change the state of my reducer with the new values 'rooms'
The way to work around this is to convert the callback into a promise. redux-saga knows how to resolve promises that you pass to the call effect. But call takes a function, not a promise. From the docs:
If the result is a Promise, the middleware will suspend the Generator until the Promise is resolved, in which case the Generator is resumed with the resolved value. or until the Promise is rejected, in which case an error is thrown inside the Generator.
var roomRef = firebase.database().ref('/Users/' + userid + '/rooms')
var rooms = yield call(function() {
return new Promise(function(resolve, reject) {
roomRef.once('value', function (snap) {
var rooms = []
var roomkeys = snap.val()
for (var roomkey in roomkeys) {
firebase.database().ref('/Rooms/' + roomkey).once('value', function (item) {
rooms.push(item.val())
})
}
resolve(rooms)
})
})
})
yield put({type: 'LOAD_ROOMS', payload: { rooms: rooms}})

Meteor reactive publish

This Meteor code displays a message on a headerLabel on a template, the server and/or the client changes the message by inserting a new message in HeaderLabelCol mongo collection and expect the client template to change since it publishes the last inserted document.
I was able to insert a new message using the client browser but did not show till I refreshed the page which may indicate that the reactiveness chain is broken somewhere. What is the problem? How can it be fixed? Thanks
//client.js
Template.header.helpers({
headerLabel: function () {
return HeaderLabelCol.findOne() ? HeaderLabelCol.findOne().headerLabel : 'Make a selection';
}
});
//server.js
HeaderLabelCol = new Mongo.Collection('headerLabelCol');
Meteor.publish('headerLabelCol', function () {
return HeaderLabelCol.find({userId: this.userId}, { sort: { createdAt: -1 } });
});
HeaderLabelCol._ensureIndex({createdAt: -1});
HeaderLabelCol.before.insert(function (userId, doc) {
doc.userId = userId;
doc.createdAt = Date.now();
});
HeaderLabelCol.allow({
insert: function (userId, doc) {
return (userId && doc.owner === userId);
}
});
I think you need to add the condition in your helper as well.
//client.js
Template.header.helpers({
headerLabel: function () {
var result = HeaderLabelCol.findOne({}, { sort: { createdAt: -1 } });
return result ? result.headerLabel : 'Make a selection';
}
});

Should I use a global "currentUserId" var in my Meteor publish code?

In my \server\publications.js file, I've got code like this:
Meteor.publish("jobLocations", function () {
var currentUserId = this.userId;
return JobLocations.find({createdBy: currentUserId});
});
Meteor.publish("workers", function () {
var currentUserId = this.userId;
return Workers.find({createdBy: currentUserId});
});
. . .
IOW, I'm using a local var named "currentUserId" in each publish method.
Would it be preferable to change it to this:
var currentUserId = null;
Meteor.publish("jobLocations", function () {
currentUserId = this.userId;
return JobLocations.find({createdBy: currentUserId});
});
Meteor.publish("workers", function () {
currentUserId = this.userId;
return Workers.find({createdBy: currentUserId});
});
...or is there some reason why each publish method needs its own local "currentUserId" var?
Due to JavaScript functions running to completion there would be no issue in using a global as long as there is no callback and it is a primitive value (not an object as you may have issues with pass-by-sharing and asynchronous functions altering this object).
In your case it is irrelevant as challett pointed: You use the var immediately so no need to declare it in the first place.

Returning undefined object from a firebase snapshot

I implemented a function where I want to return an object saved under a certain url. In the code below, the first 'console.log(result);' returns the right object from the firebase location. The second one return undefined. Can somebody explain why and how to fix it?
_getById: function(obj) {
var url = "https://my-app.firebaseio.com/list/" + obj.groupId;
console.log(url);
var ref = new Firebase(url);
var result = {};
ref.on("value", function(snapshot) {
result = snapshot.val(); //first
console.log(result);
}, function (errorObject) {
}
);
console.log(result); //second
return result;
},
The data is loaded from Firebase asynchronously. So you'll notice that your second console.log() displays before the first one. You cannot return data that is being loaded asynchronously.
You'll have to change the way you code. Instead of "get the id, then do something with it", you need to "do something whenever the id is loaded/changed".
So instead of:
var list = _getById({ groupId: 42});
console.log("Our list is: "+list);
You'll:
_getById({ groupId: 42 }, function(list) {
console.log("Our list is: "+list);
});
_getById: function(obj, callback) {
var url = "https://my-app.firebaseio.com/list/" + obj.groupId;
console.log(url);
var ref = new Firebase(url);
var result = {};
ref.on("value", function(snapshot) {
result = snapshot.val(); //first
callback(result);
}, function (errorObject) {
});
console.log(result); //second
return result;
},
In the above code we're passing a callback into _getById() and invoke that callback when the list has loaded (and whenever the list changes).
Some further reading material:
Polymer Firebase: Print async data
Asynchronous access to an array in Firebase
Trying to get child records from Firebase
Handling Asynchronous Calls (Firebase) in functions

Correct usage of Meteor wrapAsync

The following is what I am trying to do:
var joinNetwork = function (obj) {
Meteor.call("joinNetwork", {
userId: obj.userId,
domain: obj.domain
}, function (err, networkId) {
return networkId;
});
}
Accounts.onCreateUser(function (options, user) {
var userId = user._id;
var email = options.email;
var domain = Utils.getDomain(email);
var joinNetworkSync = Meteor.wrapAsync(joinNetwork);
// works fine until here
var networkId = joinNetworkSync({
userId: userId,
domain: domain
});
// never get here
debugger
As you can see, after I call joinNetworkSync I never reach the code after it. In other words, networkId is never available. What am I doing wrong?
To return from a wrapAsync you have to call a callback passed to that function:
Meteor.wrapAsync(function (obj, done) {
Meteor.call("joinNetwork", {
userId: obj.userId,
domain: obj.domain
}, function (err, networkId) {
done(networkId);
});
})
You don't need wrap async here dough. When you call meteor methods server side, they return like normal functions. You can just do this if the joinNetwork method is properly defined:
Accounts.onCreateUser(function (options, user) {
var userId = user._id;
var email = options.email;
var domain = Utils.getDomain(email);
var networkId = Meteor.call("joinNetwork", {
userId: obj.userId,
domain: obj.domain
});
...
})
I think your sync version of joinNetwork is not returning anything. You placed a return inside another function, the callback of joinNetwork. Try splitting the next part up in another function and call that inside the callback function using the networkId.

Resources