Tip: patch Meteor.user() to be less reactive (client) and more efficient (server)

Following on from a reply by @veered in another thread I wanted to share a tip to new Meteor developers but didn’t want to hijack that thread.

This is very true, over-use of Meteor.user() in template render functions can make the template overly reactive.

What can be worse, if you store lots of data on the user object (like I do) then using Meteor.user() on the server can be a very expensive db operation when often only a single field is required.

That is why I patch Meteor.user() to only return the required fields:

// Patch Meteor.user to allow filtering of fields to be more db efficient & less reactive
Meteor.user = function(fields) {
	if (Meteor.isDevelopment && !fields) console.warn('Meteor.user() called with unlimited fields');
	const userId = Meteor.userId();
	return userId ? Meteor.users.findOne(userId, {fields: fields||{}}) : null;
}

Include this patch in your server and client code, then you can do a much more efficient operations such as:

// e.g. in a template render function:
const userName = Meteor.user({"profile.name": 1}).profile.name;

// e.g in a server method, try to fetch all the required fields in one go:
const user = Metor.user({"profile.name": 1, "emails.address": 1)};
sendEmail(user.emails[0].address, user.profile.name, ...);

This is heavily inspired by peerlibrary:user-extra by @mitar (announced here). The difference is that my version includes a console warning to help you track down in your code unoptimized calls to Meteor.user(), which has proven very useful to me over the years when I write new code and forget to limit the fields.

If you want to fetch the full object without a console warning, just use “Meteor.user({})”.

There is a feature request to roll peerlibrary:user-extra into Meteor core, but again, that doesn’t include the helpful console warning.

Give it a go - you might be surprised how many times your code is calling Meteor.user()

4 Likes

Hello, thank you for the tip and the explanation, nevertheless I’m bit confused

For a simple application todo like the first meteor tutorial, what field changes during the page refresh ? when in loginTokens, ok, could be. But the userId and the username, for example, always stay the same, the client side store it, how is it possible that it appears undefined, then get called 2 times more when I refresh ? Are we just supposed to not pay attention to this until we feel that it disrupts the well functioning of what we’ve coded ?
Perhaps I should just ignore it, chill out and code ?

It also depends on how many publish functions are responsible for populating the full user object on the client - it may be that loginTokens, user.profile and username are published to the client in different publish functions, plus your own publish functions sending your custom user data to the client when they log in. Hence multiple updates to the client’s copy of the user object resulting in multiple re-renders of the template.

I’ve replied with more detail specific to your current problem in your other thread…

As to whether you should ignore the problem - in a simple demo application feel free to ignore it. However as the application grows and more data gets stored on the user object, it’s good to be aware how that is impacting the efficiency of template render functions and server database fetch operations, and to get in to good habits of making both as efficient as possible from the start.