Reputation: 108
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
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