apollographql / meteor-integration

🚀 meteor add apollo
http://dev.apollodata.com/core/meteor.html
108 stars 45 forks source link

Optimize getUserForContext to fetch the minimun required user fields #118

Open j0nd0n7 opened 6 years ago

j0nd0n7 commented 6 years ago

For every request made by a logged in user getUserForContext fetch the entire user doc. Normally only the userId (+ a role flied) is relevant for access controlling.

It would be more performant if getUserForContext fetch the minimum required fields for this package to work properly as well as allowing the developer to configure additional fields to fetch wich are required by the app.

/label feature

j0nd0n7 commented 6 years ago

Hi @lorensr since Meteor "recently" supports $expr by Mongo 3.6 and now 4.0, I'm using this query to delegate token checking to mongo and fetch only the minimum required user fields.

export const getUser = async (loginToken, fields) => {
  if (!loginToken) return null;
  check(loginToken, String);

  const hashedToken = Accounts._hashLoginToken(loginToken);
  const tokenLifetime = Accounts._getTokenLifetimeMs();
  return await Meteor.users.rawCollection().findOne(
    {
      'services.resume.loginTokens.hashedToken': hashedToken,
      $expr: {
        $ne: [
          {
            $size: {
              $ifNull: [
                {
                  $filter: {
                    input: '$services.resume.loginTokens',
                    as: 'token',
                    cond: {
                      $and: [
                        {$eq: ['$$token.hashedToken', hashedToken]},
                        {$lt: [new Date(), {$add: ['$$token.when', tokenLifetime]}]},
                      ],
                    },
                  },
                },
                [],
              ],
            },
          },
          0,
        ],
      },
    },
    {fields},
  );
};

I think it would be a nice addition to integrate something like this using either:

Let me know what do you think. Regards

lorensr commented 6 years ago

Oh cool! Didn't know you could do that with Mongo. Not sure if the speed improvement is worth the added complexity—perhaps the rare cases in which the JS logic is a speed problem can find this issue and use your code.

I like the fields, maybe as

export const getUser = async (loginToken, { fields } = {}) => {

to provide for future options in the second arg

j0nd0n7 commented 6 years ago

Note it's not only js processing, you save the network bandwidth required to retrieve the user object, for all the request that require token verification. Depending on the application, that requests could be the majority.