Replies: 3 comments 4 replies
-
Would this also help with the current situation of sorting groups, i.e. #7628, or is that out of scope? For my specific case, I'd like to sort by most recently updated group. I'm using: allPost(sort: { order: DESC, fields: date }) {
group(field: category___name) {
nodes {
...NavFrontmatter
date(fromNow: true)
dateSort: date(formatString: "X")
}
}
} and then sorting with JS by the |
Beta Was this translation helpful? Give feedback.
-
Hi 👋 @pieh, sort: {fields: [$sortBy], order: [$order]} which was valid and working well. What should that be transformed into? sort: [{$sortBy: $order}]
sort: [{[$sortBy]: $order}] but none of them works, getting: Syntax Error: Expected Name, found "$"
Syntax Error: Expected Name, found "[" Any idea of how to use a query param as the key of the sorting object? |
Beta Was this translation helpful? Give feedback.
-
Am I correct that
|
Beta Was this translation helpful? Give feedback.
-
Summary
We would like to introduce breaking change to Gatsby GraphQL schema for the next major of Gatsby that will lower resources usage and speed up “building schema” build step. The change would be applied to
sort
argument and to aggregation’sfield
argument. Instead of currently used enums to select a field, I propose using nested input objects.Basic example
Sort:
Current:
Proposed:
Aggregation:
Current:
Proposed:
Try it out
Install
gatsby
canary:With NPM:
OR with Yarn
Add
GRAPHQL_NESTED_SORT_AND_AGGREGATE
to feature flags ingatsby-config
:After installation and adding feature flag, you can run
gatsby build
orgatsby develop
. If tested on a site with queries that includesort
or any of aggregation fields, there will be errors about queries not matching schema anymore, but ingatsby develop
you can play with new API shape in GraphiQL ( http://localhost:8000/___graphql )We provide a codemod to convert previous shape of API to new one, it’s optional but recommended especially if you want to test this on existing site. To try it:
Install
gatsby-codemods
canary in the site directory:With NPM:
OR with Yarn
With
gatsby-codemods
canary installed, Gatsby will transform old API shape on-the-fly. Runninggatsby build
orgatsby develop
should not show any query errors, apart from webpack’s eslint plugin that will show warnings ingatsby develop
:Using on-the-fly transformation is meant just as a stop-gap, to be able to play with feature on existing site without having to migrate all of it just yet. However if you want to keep using it, You should apply transformation to your files, so Gatsby doesn’t have to do it on-the-fly (and will allow to remove
gatsby-codemods
package from dependencies.To apply transformation to your files:
(optional) commit or stash any changes in your project to start with clean working directory, to be able to easily inspect changes that transformation did
run
OR
(optionally) run your formatter of choice on changed files ( codemod might break your code style )
If you are curious to see example results of codemod - check a change that id produced to
gatsby-starter-blog
- https://github.com/pieh/gatsby-starter-blog-new-sort-and-aggr/commit/79679894bb0c829150742dbf17d8360e8cb4a9beCodeSandbox
gatsby-starter-blog
with canaryMotivation
Primary motivation (to change current API)
To make current API work we need to traverse all possible combination of nested fields (up to 3 levels deep) and generate all possible path combinations. That can become quite expensive and this can result in quite slow “building schema” build step. GraphQL schema also need to retain all those possible values in memory (which is made worse by Parallel Query Running as GraphQL schema is generated separately for each process).
To demonstrate the impact I created small reproduction using learnings from debugging a user’s site that has a lot of relationship links on data ( https://github.com/pieh/change-sort-and-aggregation-demo/blob/main/gatsby-node.js ).
The memory usage with setup like this is very high:
After testing proposed GraphQL schema change:
The change also lowered time needed to build schema from ~15s to ~0.3s.
TL/DR: Main motivation is increasing performance of “building schema” and lowering memory usage
Secondary motivation
Proposed change is also trying to unify our API bringing
sort
and aggregation fields to shape similar tofilter
It also removes the limitation of maximum 3 levels of nesting when selecting fields to sort or aggregate on.
Detailed design
Sort:
Prior art - Hasura
filter
API, we will re-use the generation offilter
argument type forsort
eq
,in
, etc) user will be able to provide eitherASC
orDESC
to decide the order (this will also make the sort order explicit - currently users can skip declaring order and we will default toASC
)@oneOf
directive if it ships to GraphQL spec /graphql-js
. For now we will have to resort to throwing when trying to execute (with@oneOf
being in spec, we can rely on GraphQL tooling to provide hints about that earlier - in GraphiQL or various IDEs integrating GraphQL support)sort
type will be a list (array) to support sorting on multiple fields - each item in array will be full nested object. GraphQL is coercing single element in query text to array so users won’t need to use array syntax if they sort on single fieldsort
resolver will be adjusted to support new notationAggregation fields:
(
group
,distinct
,min
,max
,sum
)Didn’t really find matching Prior art for this - Hasura has quite interesting approach which we could replicate for our aggregation fields except for
group
. I think there is value in keeping our fields feel similar across our APIs and because of that I propose following shape of aggregation fields that closely matchesfilter
and proposedsort
changesfilter
API, we will re-use the generation offilter
argument type for aggregation fieldseq
,in
, etc) user will be able to provide just single value to select a field to aggregate on -SELECT
(true
which was my first choice, can’t be used because of limitations to possible enum values in GraphQL)sort
, for aggregation fields will ensure one and only one field is ever setsort
) as we can aggregate just on one fieldDrawbacks
sort
in particular is one of core APIs that is used almost on every site, so “reach” is high:sort
(either directly or just accidentally) will become outdatedAlternatives
Not address this problem. This doesn’t seem like viable option. We made lot of progress in scaling various systems over the years to make it feasible to build really big and complex site with Gatsby and we want to continue that scaling. Both performance penalty and high memory usage are very real blockers that need to be addressed.
Address the problem by lowering maximum depth level of nested fields (currently 3) used to generate fields to sort on and/or making it user configurable
This is “easiest” solution in terms of implementation, but it puts user in awkward position where they might need to do impossible choice of either having access to a feature (sorting on deeply nested fields) or the build performance (and cost because of the need for more memory usage ). This would not be a breaking change
Allow users to mark fields as not sortable/aggregable (or reverse of it - make every field not sortable/aggregable by default and force user to define which fields should be sortable/aggregable). This would likely need to work via GraphQL directives/extensions which forces user to deal with Schema Customization for basic tasks that “should just work” - discarded because of poor DX with this approach. The first approach (removing fields from being sortable) is not a breaking change. The reverse approach is.
Changing current Enums to String fields. We could preserve most of the syntax, just require wrapping it with quotes to become a string. This would be a breaking change (at very least quotes would need to be added to queries) and DX when using a GraphQL tooling would be much worse as there could not be any suggestions provided or linting and user would have to “guess” the path. Very error-prone. Prior art - Tina GraphQL API, Gridsome
Very similar design to one proposed in this RFC, with difference that
sort
wouldn’t accept a list and wouldn’t have requierment for one and only one field being selected - it would have requirement of at least one field being selected. Field priority/weight would be set concretely on a leaf:This syntax is more verbose for sorting on single field than proposed one ( instead of just
ASC
there would be a need for{ order: ASC }
), but becomes less verbose than proposed one with 2+ fields to sort on especially when sorting on nested fields. Due to sorting at most by one field being dominant type of queries my proposal is to optimize for that. Aside from verbosity, I think that separating each field to sort on is more common in various technologies ( SQL,lodash/orderBy
) than using aweight
which should make it easier to teachAdoption strategy
This is a BREAKING CHANGE and will require users to migrate. We will need a migration guide.
We will provide codemods to automatically convert queries (this already works). See “Try it out” section.
We will provide compatibility mode to apply the codemod automatically so the site will continue to build, but a lot of tooling won’t be able to use it (GraphiQL wouldn’t understand old syntax and would show errors, graphql eslint plugin likely would consider queries with old syntax invalid). To enable compatibility mode
gatsby-codemods
will need to be installed in a site, sogatsby
can apply transforms provided bygatsby-codemods
The main purpose of Compatibility Mode would be to allow user to start dev server that works enough to show the site / try optimistic bump in a PR to see what happens in CI. Lot of features won’t work correctly (GraphiQL, Eslint plugin), so applying codemod permanently is preferred.
How we teach this
gatsby@5
migration guide.Beta Was this translation helpful? Give feedback.
All reactions