4

I have a Gatsby GraphQL query for a list of posts ordered by date and filtered by category.

{
  posts: allContentfulPost(
    sort: {fields: [date], order: DESC},
    filter: {category: {slug: {eq: $slug}}}
  ) {
    edges {
      node {
        title {
          title
        }
        date
      }
    }
  }
}

Right now when $slug is the empty string "", I get

{
  "data": {
    "posts": null
  }
}

Is there a way to get all posts instead?

Janosh
  • 3,392
  • 2
  • 27
  • 35

3 Answers3

6

You can use the regex filter to your advantage. If you pass an empty expression, then all posts will be returned because everything will match.

query Posts($slugRegex: String = "//"){
  posts: allContentfulPost(
    sort: {fields: [date], order: DESC},
    filter: {category: {slug: {eq: $slugRegex}}}
  ) {
    # Rest of the query.
  }
}

By default, all posts will be returned (the $slugRegex is an empty regex if nothing was passed). When the $slugRegex becomes a meaningful expression, then only matching posts will show up.

As for passing the value, I'm assuming you're using gatsby-node.js to create pages. In that case, it's as simple as that:

// gatsby-node.js

exports.createPages = async ({ actions }) => {
  const { createPage } = actions

  // Create a page with only "some-slug" posts.
  createPage({
    // ...
    context: {
      slugRegex: "/some-slug/"
    }
  })

  // Create a page with all posts.
  createPage({
    // ...
    context: {
      // Nothing here. Or at least no `slugRegex`.
    }
  })
}
Mateusz Kocz
  • 4,492
  • 1
  • 25
  • 27
  • 1
    Your answer helped me a lot figuring out a solution. In my case, I used a regex too but in the filter I've use the term `regex` instead of `eq`, so based on your example it's: `filter: {category: {slug: {regex: $slugRegex}}}` – Cyril F Feb 04 '20 at 17:53
2

If anyone requires a solution for other systems than Gatsby this can be accomplished using @skip and @include.

fragment EventSearchResult on EventsConnection {
  edges {
    cursor
    node {
      id
      name
    }
  }
  totalCount
}

query Events($organizationId: UUID!, $isSearch: Boolean!, $search: String!) {
  events(condition: { organizationId: $organizationId }, first: 100)
    @skip(if: $isSearch) {
    ...EventSearchResult
  }
  eventsSearch: events(
    condition: { organizationId: $organizationId }
    filter: { name: { likeInsensitive: $search } }
    first: 100
  ) @include(if: $isSearch) {
    ...EventSearchResult
  }
}

Then in your client code you would provide search and isSearch to the query and get your events like:

const events = data.eventsSearch || data.events
DylanVann
  • 483
  • 5
  • 9
1

It's not possible with this query, even @skip/@include directives won't help because you can't apply them on input fields.

I would suggest to either adjust the server side logic so that null in the 'eq' field will ignore this filter or either to edit the query being sent (less favorable imo).

It seems that the graphql schema that you work against lacks the filtering support you need..