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
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
Hi @philippdhh,
Did you find a way to do this?
Thanks,
Jaime
@j-franco-applaudo Unfortunately I have not solved this problem yet. I would as well still be interested in a solution,.
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();
}
});
};
@philippdhh Can I close this? Did you try what @abovegradesoftware suggested?
I know that hook works. It's safe to close this. It would be nice to add this functionality into the stock product.
Sounds good, I'll change this from triage to a feature request. TY
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.
Maybe we could work on a mixing that will add this functionality?
What would be the best way to start on this?
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.
I have found this.
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
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.
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.
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();
}
});
};