I have some subscriptions I need to refresh when a user changes roles. Since the user now has a new role I need to republish the subscriptions as they take role into account. Here is what I'm attempting to do:
Tracker.autorun(function(){
Meteor.users.find({_id: Meteor.userId()}, {fields: {"roles": 1}});
console.log("You changed roles, republishing data");
Meteor.subscribe('pendingUsers');
});
I'm using alanning:roles. It seems to work in some situations but not others. One situation that doesn't trigger this to run is when I alter the users roles from "meteor shell". What am I doing wrong? Is there a better way to do this?
You need to make something change within your subscribe(). See docs:
However, if the next iteration of your run function subscribes to the same record set (same name and parameters), Meteor is smart enough to skip a wasteful unsubscribe/resubscribe.
Related
I'm sure these are common scenarios, but after researching some hours, I couldn't really find what the common practice is. Maybe someone with more experience in Firebase can point me to the right direction.
I have two particular scenarios:
1. Code that runs once
Example 1: adding new data to all users in firestore, which is needed for a new feature
Example 2: start duplicating data into existing documents
I currently write the code in a cloud function, and run it on a firestore event (onUpdate of a "hidden" document) and then I immediately delete the function if everything goes well.
I also increase the timeout and memory for this function, as the idea is to potentially update millions of documents.
2. Manually trigger a function from the firebase console (or command line)
Example: Give a user admin privileges in the app (function that sets custom claims and firestore data). We don't have time to implement a back-office, so doing this from the firebase web portal/console would be ideal, specifying the user id.
My current solution is to use a https function, and run it from the GCP portal (on the function's "Testing" tab, being able to pass a json). BUT the function can be triggered publicly, which I don't really like...
What are the common practices for these scenarios?
To expand on my comment: if you want to create a node script to run one-off code, you just write your JS code like for any cloud function but simply run it immediately. Something like this.
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
db.collection('users')
.where('myField', '==', true)
.get()
.then(querySnapshot => {
querySnapshot.docs.forEach(doc => {
// update doc
});
});
If you save this as script.js and execute it with node script.js you’ll be pointed towards downloading a JSON file with credentials. Follow the instructions and you can then run the script again and now you’re running your own code on Firestore, from the command line.
For administrative type operations, you're better off just running them on your desktop or some other server you control. Cloud Functions is not well suited for long running operations, or things that must just happen once on demand.
Case 1 really should be managed by a standalone program or script that you can monitor by running it on your desktop.
Case 2 can be done a number of ways, such as building your own admin web site. But you might find it easiest to mirror the contents of a document to custom claims using a Firestore trigger. Read this: https://medium.com/firebase-developers/patterns-for-security-with-firebase-supercharged-custom-claims-with-firestore-and-cloud-functions-bb8f46b24e11
When a user registers on my system, I create the user internally, and then allow the user to register with Firebase using the firebase client lib. This generates a session token for the user. Later, when a user starts the app again, the app automatically logs the user in like this:
ref.authWithCustomToken(sessionToken, function(error, authData) {...
debugger
I have verified that the sessionToken is available when the function is executed, but debugger is never reached, and no error is ever emitted.
Any help is appreciated!
I know it's a bit late, but I experienced a similar problem and it had me scratching my head for a while, so just in case it helps somebody else, here's what I found.
If I run authWithCustomToken with a token generated with one uid (uid1) and then run it again on the same ref with a different uid (uid2), the callback doesn't get fired the second time around.
In my case, I had declared the same ref in different modules that were used in the same node process and was trying to authenticate them with different uids. Although I had declared the ref twice, Firebase still saw it as the same ref because it was in the same process and referred to the same Firebase location. By declaring and authorising the ref in a parent module, I was then able to use onAuth in the child modules and the onAuth callbacks all fired as expected.
I had a similar problem with iOS, authWithCustomToken callback was never called right after install.
All consecutive launches worked fine.
My findings might be related so I thought I share them.
Problem was I called
func applicationWillResignActive(application: UIApplication) {
Firebase.goOffline()
}
func applicationWillEnterForeground(application: UIApplication) {
Firebase.goOnline()
}
in AppDelegate. Turns out if you call Firebase.goOnline() without logging in first it messes up the callback. Once I removed those two lines everything worked fine.
Or will it cause an error?
Example:
authClient = new FirebaseAuthClient(baseRef, function(error, user) { ... });
// Try to log in...
authClient.login('password', {email: 'some_email', password: 'some_password'});
// Before the callback from the previous line of code executes...
// Oh wait, I forgot to signup in the first place, let me do that:
authClient.createUser('some_email', 'some_password', function(error, user) { ... });
While it is safe to call those methods before the previous one has completed, in that you won't break corrupt data nor will exceptions be thrown, you might see some unexpected (and non-deterministic) behavior, depending upon the state of the user's account and session.
For example, if an existing session is detected (via looking at the browser cookie and localStorage), the FirebaseAuthClient will attempt to resume it which involves a quick verification step. Calling login before that step has completed will have different effects depending upon the user's account status.
Continuing that example, if the account exists and credentials are correct, you'll override the existing session and your callback will be invoked twice (once for the existing session, and once for the new one). If the account does not exist, or the credentials are incorrect, you may first receive one callback for the correct session, and then an error after receiving the bad credentials.
It might be helpful to hear a bit more about your specific use case and desired user experience so we may determine the clearest way to structure your code. Hope that helps!
Basically, I need to initiate a background process when a user logs in. The background process returns some sensitive data, the server side should further process it and then make it available for the client.
Is this where Meteor.Publish and Subscribe methods come into play? Or do I need to use Meteor.methods? Are there any other approaches?
For this kind of thing you might want to use a call instead of a publish. This is because the use case of the publish function is more to decide what the user should see & not really to process data (i.e do a web scrape or something and collect this) & the process might be blocking so all clients might to wait for this task to finish.
I would suggest you migrate over to meteorite: https://github.com/oortcloud/meteorite via
npm install -g meteorite
You would now have access to the wonderful collection of community packages at http://atmosphere.meteor.com.
Ted Blackman's event-horizon package lets you create events when the user logs in on the client.
You can then create an event for this:
Client Js
EventHorizon.fireWhenTrue('loggedIn',function(){
return Meteor.userId() !== null;
});
EventHorizon.on('loggedIn',function(){
Meteor.call("userloggedin", function(err,result) {
console.log("Ready")
if(result) {
//do stuff that you wanted after the task is complete
}
}
});
Server js
Meteor.methods({
'userloggedin' : function() {
this.unblock(); //unblocks the thread for long tasks
//Do your stuff to Meteor.user();
return true; //Tell the client the task is done.
}
});
We have a problem with our meteor server. When we publish 300 or so items with Meteor.publish/Meteor.subscribe the server increases its memory and eventually becomes unresponsive.
We thought of:
1) monitor the number of reactive subscribtions / memory taken by an active subscription
2) make something like ,,one time publish" - ignore changes in server side collection
Any thoughts on how any of the above can be accomplished ?
Or any other tips to debug /improve meteor app performance ?
Thanks
zorlak's answer is good.
Some other things:
You can do a one-time publish by writing your own custom publisher via the this.set API, based on the code in _publishCursor. You'd do something like:
Meteor.publish("oneTimeQuery", function () {
MyCollection.find().forEach(function (doc) {
sub.added("collectionName", doc._id, doc);
});
sub.ready();
});
This does a query, sends its results down, and then never updates it again.
That said, we hope that Meteor's performance will be such that this is unnecessary!
I'd also like to add an easy way to get stats (like number of observed cursors) from an app to Meteor (exposed as an authenticated subscription) but haven't had the time yet.
As of Meteor 0.5.1, one thing you can do is to remove dependencies on the userId from the publish function. If a publish function does not depend on which user is subscribing, then Meteor will cache the db query so it doesn't get slower as more users subscribe.
See this Meteor blog post: http://meteor.com/blog/2012/11/20/meteor-051-database-scaling