Most performant way to check for an existing document in a collection?

Hi Meteor folks,

We have spotted some bottlenecks in our production app regarding the check for an existing document in a collection.

currently we have a simple helper function like the following:

export const isExistingUserId = async (id: string): Promise<boolean> => {
    return (await Meteor.users.find(id, { limit: 1 }).countAsync()) > 0;
};

This does not seem to be well written (code base goes back to 6 years…) and furthermore, deprecated :confused:

Thanks to Monti APM we have seen, that these kind of checks take up a big chunk of “response time”.

image

What would be the smarter way to implement such checks?

Alternative with findOneAsync?

export const isExistingUserId = async (id: string): Promise<boolean> => Boolean(await Meteor.users.findOneAsync(id, { fields: { _id: 1 } }));

Alternative to the deprecated CountAsync?

Some insights / best practices are kindly welcome.

We are checking the existence of a document in this way for now…

export const isExistingUserId = async (userId: string): Promise<boolean> => {
    return typeof userId === 'string' && Boolean(await Meteor.users.countDocuments({ _id: userId }));
};

About the countAsync, if you’re using Meteor 3, we’re using countDocuments under the hood. So no deprecated methods is being called.

Did you check the response time for this? Is it better?

What about trying findOneAsync?

export const isExistingUserId = async (userId: string): Promise<boolean> => {
    return typeof userId === 'string' && !!(await Meteor.users.findOneAsync(userId, { fields: { _id: 1 } }));
};

This should be fast if you have the _id indexed (it should be by default). And I believe it should be faster than countDocuments, but you could test and share it with us the results :slight_smile:

We are still on Meteor v2.14 … but refactored a lot of code to be able to upgrade to v3 (still a few packages that are blocking us from upgrading)

The findOneAsync version was way slower than the currently used countDocuments implementation.

findOneAsync - 1676ms

countAsync - 1300ms
image

countDocuments - 36ms
image

One important remark for the current implementation:

  • we are now using this.unblock() whenever appropriate
  • we switched from using Collection.find... to Collection.rawCollection().find... in our server methods

Overall performance has been increased, but still some bottlenecks (probably CPU / Server ressources)