1
votes

I'm new to GraphQL and Gatsby and looking to understand programmatic approach to "joining" data from two different sources in my Gatsby project. I have an albums.json file that I am querying as follows:

query MyQuery {
  allAlbumsJson(sort: {fields: releaseDate, order: DESC}) {
    edges {
      node {
        id
        title
        slug
        releaseDate
      }
    }
  }
}

I also have a markdown file for each album whose path is dynamically generated. How can I pull in fields from my markdown files into the above query based on, say, the title field, which is part of the frontmatter for the markdown?

If I have to make explicit connections between the nodes generated by the gatsby-transformer-json plugin and the ones generated by the gatsby-transformer-remark plugin, how and where would I do that? I've been looking at similar questions but still am stumped as to the most efficient way to do this. Thanks for your help!

1

1 Answers

0
votes

You don't need to make extra explicit connections. gatsby-node.js APIs allows you to, among other things, create dynamic pages as you are doing. In this case, you JSON will be the source from where your album pages will be generated. Something like:

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  const result = await graphql(`
   query {
     allAlbumsJson(sort: {fields: releaseDate, order: DESC}) {
       edges {
         node {
           id
           title
           slug
           releaseDate
         }
       }
     }
   }
 `)
  result.data.allAlbumsJson.edges.forEach(({ node }) => {
    createPage({
      path: `/album/${node.fields.slug}`,
      component: path.resolve(`./src/templates/album.js`),
      context: {
        title: node.fields.title,
      },
    })
  })
}

Modified from: https://www.gatsbyjs.com/docs/tutorial/part-seven/

With the snippet above, you are querying all albums via GraphQL and creating pages for each album based on the slug field in /album/${node.fields.slug}. Then, you are letting know Gatsby which template will hold your template logic (/templates/album.js). Gatsby allows you to send data to the pages and templates using the pageContext (context), which will be used to filter the markdowns. In this case, we are sending the title, as you said.

In your template, now you just need to get the passed field and fetch the data:

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

export default function Album({ data }) {
  const album = data.markdownRemark;
  console.log("your album data is", data);

  return (
    <Layout>
      <div>
        <h1>{album.frontmatter.title}</h1>
      </div>
    </Layout>
  )
}
export const query = graphql`
  query($title: String!) {
    markdownRemark(fields: { title: { eq: $title } }) {
      html
      frontmatter {
        title
      }
    }
  }
`

*Note: the query can be different since I'm modifying the code based on Gatsby's tutorial without knowing your data structure. Test it in the GraphQL playground at localhost:8000/___graphql*

The key part is on the GraphQL query side. You are telling GraphQL that will receive a non-nullable (like required, spotted with the exclamation mark, !) string, which is $title. If the filesystem is set properly, Gatsby, at the build-time, will be able to generate GraphQL nodes (markdownRemark) and you can filter them by the field you are sending for each album from your gatsby-node.js.