Gatsby: GraphQL query - sort nulls last

Created on 14 Apr 2018  路  4Comments  路  Source: gatsbyjs/gatsby

Hi everyone, I'm so impressed with Gatsby! I'm just having an issue where I'm sorting Contentful items by date (descending), but date isn't a required field. Items without a date (returning a null value) are at the top of the list. Is there an option for having 'nulls last' when sorting?

Here's the code for my query:

query categoryItemsQuery($slug: String!) {
  allContentfulPortfolioItem(
    filter: { categories: { slug: { eq: $slug } } },
    sort: {fields: [date], order: DESC}) {
    edges {
      node {
        id
      }
    }
  }
}

Sorry if this is the wrong place to post this! Thanks for all your hard work.

help wanted

Most helpful comment

You have currently 2 options:

  • make 2 separate queries (1 for sorted items with date and second for items without date) and concatenate them in your page component:
query categoryItemsQuery($slug: String!) {
  withDate:allContentfulPortfolioItem(
    filter: { categories: { slug: { eq: $slug } }, date: { ne: null } },
    sort: {fields: [date], order: DESC}) {
    edges {
      node {
        id
      }
    }
  }
  withoutDate:allContentfulPortfolioItem(
    filter: { categories: { slug: { eq: $slug } }, date: { eq: null } }) {
    edges {
      node {
        id
      }
    }
  }
}

and then in your component use this.props.data.withDate and this.props.data.withoutDate

  • or add sortDate field to your Portfolio Item node in gatsby-node.js:
exports.onCreateNode = ({ node, boundActionCreators }) => {
  const { createNodeField } = boundActionCreators
  if (node.internal.type === `NameOfType`) { // name of type you can get in graphiql in docs section or by ctrl+clicking on `node` field in your query
    createNodeField({
      node,
      name: `sortDate`,
      value: node.date || "1970-01-01", // either date if node has this field or very early date that should be before any of the date in content
    })
  }
};

and then sort by fields__sortDate

All the examples are written without testing, so this might not work out of the box - but hope approaches are readable

All 4 comments

You have currently 2 options:

  • make 2 separate queries (1 for sorted items with date and second for items without date) and concatenate them in your page component:
query categoryItemsQuery($slug: String!) {
  withDate:allContentfulPortfolioItem(
    filter: { categories: { slug: { eq: $slug } }, date: { ne: null } },
    sort: {fields: [date], order: DESC}) {
    edges {
      node {
        id
      }
    }
  }
  withoutDate:allContentfulPortfolioItem(
    filter: { categories: { slug: { eq: $slug } }, date: { eq: null } }) {
    edges {
      node {
        id
      }
    }
  }
}

and then in your component use this.props.data.withDate and this.props.data.withoutDate

  • or add sortDate field to your Portfolio Item node in gatsby-node.js:
exports.onCreateNode = ({ node, boundActionCreators }) => {
  const { createNodeField } = boundActionCreators
  if (node.internal.type === `NameOfType`) { // name of type you can get in graphiql in docs section or by ctrl+clicking on `node` field in your query
    createNodeField({
      node,
      name: `sortDate`,
      value: node.date || "1970-01-01", // either date if node has this field or very early date that should be before any of the date in content
    })
  }
};

and then sort by fields__sortDate

All the examples are written without testing, so this might not work out of the box - but hope approaches are readable

It seems reasonable too to change our sorting so nodes without the sort field always are at the end.

Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!

Was this page helpful?
0 / 5 - 0 ratings