feathers icon indicating copy to clipboard operation
feathers copied to clipboard

Issues with $sort and createQuery/._find

Open michalgm opened this issue 5 months ago • 3 comments

0This may be more of a breadcrumb for others having this issue than an actual bug report, though perhaps documentation can be improved.

I was trying to modify the incoming query in a service hook, and noticed that the $sort param was not being respected properly when passed into context.service.createQuery. I had similar results using context.service.find. Note that i am using postgres via the feathers-knex provider.

When sending (from the REST client) a query like

          $select: [
            "record_id",
            "title",
          ],
          $limit: PAGE_SIZE,
          $skip: offset,
          $sort: { title: 1 },
        };

and then in my hook, creating a query using context.service.createQuery(context.params) (or with context.service._find(context.params), I noticed that the sort on title was always desc regardless of what I specified in the $sort parameter. After digging around, I found https://github.com/feathersjs/feathers/blob/dove/packages/knex/src/adapter.ts#L153

    if (filters.$sort) {
      return Object.keys(filters.$sort).reduce(
        (currentQuery, key) => currentQuery.orderBy(key, filters.$sort[key] === 1 ? 'asc' : 'desc'),
        builder
      )
    }

in the knex provider code. It seems that integers are converted into strings when passed into the API, so I was ending up with $sort: { title: "1" } which of course was failing the === 1 test.

Upon further digging, I found a pretty acceptable workaround by passing params into the (undocumented) context.service.sanitizeQuery method like so:

const params = {
    ...context.params,
    query: await context.service.sanitizeQuery(context.params)
  };
context.service.createQuery(params);

this results in the $sort param (and perhaps others) being properly interpreted.

I can definitely see why you might not want to pass the query arg to ._find or createQuery through sanitizeQuery by default, but maybe a note could be added to the docs pointing this behavior out?

michalgm avatar May 15 '25 23:05 michalgm