Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding total count to the "find all" route #1411

Closed
philippdhh opened this issue May 27, 2015 · 14 comments
Closed

Adding total count to the "find all" route #1411

philippdhh opened this issue May 27, 2015 · 14 comments

Comments

@philippdhh
Copy link

Hello,

I like to integrate ng-admin with Loopback.

To make pagination feature work I would prefer the total number of objects within a collection to be part of the response to the GET find all request and avoid a seperate call to /count.

As example if I had a resource car I would like the GET /cars route to include the total number of cars even if I use a filter for pagination.

The total count number could either be implemented in

  • additional totalCount attribute in the response body
  • X-Total-Count header in the response header

Is there any existing configuration option to enable X-Total-Count header in the find all route?
Is there any best practise to add the total count to my ressources manually?

Thank you in advance
Philipp

@j-franco-applaudo
Copy link

Hi @philippdhh,

Did you find a way to do this?

Thanks,
Jaime

@philippdhh
Copy link
Author

@j-franco-applaudo Unfortunately I have not solved this problem yet. I would as well still be interested in a solution,.

@abovegradesoftware
Copy link

You can do this with a remote hook. Here's an example:

module.exports = function (app) {
  var remotes = app.remotes();

  // Set X-Total-Count for all search requests
  remotes.after('*.find', function (ctx, next) {
    var filter;
    if (ctx.args && ctx.args.filter) {
      filter = JSON.parse(ctx.args.filter).where;
    }

    if (!ctx.res._headerSent) {
      this.count(filter, function (err, count) {
        ctx.res.set('X-Total-Count', count);
        next();
      });
    } else {
      next();
    }
  });
};

@superkhau
Copy link
Contributor

@philippdhh Can I close this? Did you try what @abovegradesoftware suggested?

@abovegradesoftware
Copy link

I know that hook works. It's safe to close this. It would be nice to add this functionality into the stock product.

@superkhau
Copy link
Contributor

Sounds good, I'll change this from triage to a feature request. TY

@superkhau superkhau added feature and removed triaging labels Jul 7, 2015
@framp
Copy link

framp commented Sep 8, 2015

It would be great to have it in core.

That hook doesn't work with nested resources.

I can get the parent and child model but then it gets really messy because I need to understand what's the current relation which is generating the route.

const match = ctx.methodString.match(/(.*).prototype\.__get__(.*)/);
    if (match) {
      const parentModelName = match[1];
      const modelName = pluralize(match[2], 1);
      model = server.models[modelName];
      const relations = model.settings.relations;
      //Check every relation for parentModelName and use it instead of parentModelName
      filter[parentModelName + 'Id'] = ctx.ctorArgs.id;
   }

Is there a better way to access the current relation or the filter which is being applied to the subresource (consisting of whatever the user defined filter is AND the filter set by the relation)?

This won't cover relations through other models, unless filtering on included models get implemented.

@alfierivera
Copy link

Maybe we could work on a mixing that will add this functionality?

What would be the best way to start on this?

@framp
Copy link

framp commented Oct 20, 2015

I'd personally start by refactoring the methods for nested and base resources - so that they can share code (there are already differences in behaviour between nested and base resources - eg. /a/1/b/2 doesn't accept filters). After all the only difference in a nested resource is just one more filter, conceptually. I find it very WET to have a specific new method.
Then I'd expose the query used to fetch data (not the actual code, just an abstract object/function which represent the request) in a hook.
With that we should be able to get the query, remove the limit and transform it from a select to a count request.

But that's a huge amount of work, given how the framework is designed.
The easiest thing would be to create a filter which checks all the possible relations and act accordingly - I suppose somewhere in the code there is something similar that can be reused.

@mrbatista
Copy link

I have found this.

@framp
Copy link

framp commented Oct 20, 2015

Cool, but doesn't really accomplish the same goal.

When talking about nested resources I meant resources accessed through a relationship (/a/1/b/2), not included resources

@martinjuhasz
Copy link

Currently running into the same problem as framp. it would be cool if a totalcount attribute could be added by configuration when a model gets queried with the limit/ skip filter, no matter if its directly queried on the endpoint or a nested resource included by scope.

@stale
Copy link

stale bot commented Sep 6, 2017

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.

@wgenius2003
Copy link

This hooks validates than ctx.args.filter is an string or not

/* eslint-disable max-len */
module.exports = function (app) {
  var remotes = app.remotes();

  // Set X-Total-Count for all search requests
  remotes.after('*.find', function (ctx, next) {
    var filter;
    if (ctx.args && ctx.args.filter) {
      if (typeof ctx.args.filter === 'string' || ctx.args.filter  instanceof String)
        filter = JSON.parse(ctx.args.filter).where;
      else
        filter = ctx.args.filter.where;
    }

    if (!ctx.res._headerSent) {
      this.count(filter, function (err, count) {
        ctx.res.set('X-Total-Count', count);
        next();
      });
    } else {
      next();
    }
  });
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants