Christian Mund
Christian Mund

Reputation: 108

GraphQL ignores some (but not all) arbitrarily assigned markdown frontmatter data

First time trying out Gatsby and it's been a pleasure. However I ran into a strange GraphQL problem:

I'm using the gatsby-source-filesystem and gatsby-transformer-remark plugins to pull in content from markdown files.

The frontmatter data is not the same across all of them (except for title). Some have a date string (the blog posts), same have a tag array, some have a gallery object.

Now the problem is that some of this arbitrarily assigned frontmatter data is available in GraphQL and some is not. For example if I try to query the date I always get the "GraphQL Error Unknown field date on type frontmatter_2". Whereas if I query the tags, I get the tag array for those items that contain one and tags: null for those who don't.

What's the problem here? How can I always get null as value of a field that doesn't exist in a node?

It's probably of note that this behaviour changes depending on the directory structure of my markdown files. If I move them around, some frontmatter fields become available in GraphQL that previously weren't and vice versa. It also happens that after some code changes get pushed via HMR, some fields become available - but after I restart Gatsby, they're gone again despite not having touched the code in-between.

Thanks a lot for helping!

Edit:

After unsuccessfully banging my head against this for some time, I resorted to ensuring that all markdown frontmatter has the same fields of the same type.

I guess the

TODO link to docs on auto-inferring types/fields.

part of the documentation is about this problem.

When I have more time, I'd like to learn more about GraphQL and how it works in Gatsby. Any pointers appreciated.

Upvotes: 4

Views: 770

Answers (1)

chmac
chmac

Reputation: 12625

You might be hitting this bug where sometimes sparsely populated fields seem to be missed from GraphQL.

However, to answer your specific question, how can you ensure that you always get null for empty fields. You could do that by using the onCreateNode hook. This hook gets called for every node.

Something like the following pseudocode will achieve your goal:

exports.onCreateNode = ({node, getNode, boundActionCreators}) => {
  const { createNodeField } = boundActionCreators

  if (_.get(node, 'internal.type') === `MarkdownRemark`) {

    // Repeat this for each field
    createNodeField({
      node,
      name: 'date',
      value: _.get(node, 'frontmatter.date', 'default date'),
    })

  }
}

This will copy values from frontmatter to fields and ensure that they are always present with some default value if they don't already exist. You can add tests on node.internal.type to filter for specific node types

NOTE: This is totally untested, off the cuff, pseudocode, use at own risk!

Upvotes: 4

Related Questions