Search code examples
javascriptgraphqlgatsby

Fetch only one element from Graphql in Gatsby


am new to gatsby and graphql and I came across a tutorial where it is mentioned to fetch all the data using .map. But I want to fetch only one element from the DB. So how do I do it?

import React from "react";
import Layout from "../components/layout";
import { useStaticQuery, graphql, Link } from "gatsby";

const Blogs = () => {
  const data = useStaticQuery(
    graphql`
      query {
        allMarkdownRemark(sort: { frontmatter: { date: ASC } }) {
          edges {
            node {
              frontmatter {
                title
                date(formatString: "DD MM, YYYY")
              }
              excerpt
              id
              fields {
                slug
              }
            }
          }
        }
      }
    `
  );
  return (
    <Layout>
      <ul>
        {data.allMarkdownRemark.edges.map((edge) => {
          return (
            <li key={edge.node.id}>
              <h2>
                <Link to={`/blog/${edge.node.fields.slug}/`}>
                  {edge.node.frontmatter.title}
                </Link>
              </h2>
              <div>
                <span>
                  Posted on {edge.node.frontmatter.date} 
                </span>
              </div>
              <p>{edge.node.excerpt}</p>
              <div>
                <Link to={`/blog/${edge.node.fields.slug}/`}>Read More</Link>
              </div>
            </li>
          );
        })}
      </ul>
    </Layout>
  );
};

export default Blogs;

Lets say I have multiple blogs and I wish to show only a specific one in a page through query like...

query MyQuery {
  markdownRemark((id: {eq: "9ac19d6d"}) //Some ID {
    title
    description
    content
  }
}

How to get this on a page to display? Thanks in advance!


Solution

  • Depending on what do you want to achieve:

    • If you want just a specific single post. You can filter your useStaticQuery to add the value of the id (if you know it beforehand) like:

      query MyQuery {
         markdownRemark((id: {eq: "123"})  {
           title
           description
           content
         }
      }
      

      useStaticQuery as the name points out, is static and doesn't accept dynamic values.

      Another alternative is to get a specific position from data.allMarkdownRemark to display it.

      If you just want a single post without any filter you can take advantage of the GraphQL query options:

        {
          allMarkdownRemark(limit: 1) {
            edges {
              node {
                frontmatter {
                  title
                }
              }
            }
          } 
        }
      
    • If you are trying to create dynamic posts, hence each post template will display a different blog post (one per template), you need to pass a filter value from gatsby-node.js (where you create the post pages) to the template through Gatsby's context:

        // gatsby-node.js
        posts.forEach(({ node }, index) => {
          createPage({
            path: node.fields.slug,
            component: path.resolve(`./src/templates/blog-post.js`),
            context: {
              id: node.id, 
              title: node.title
            },
          })
        })
      

      Note: here I'm lifting the id and the title. Use whatever works better for you

      Now, you can take advantage of the context in your Blogs component (as long as it's a template):

         const Blogs = ({data}) => {
           console.log("your blog post is:", data)
      
            return (
              <Layout>
                <h1>{data.markdownRemark.title}</h1>    
              </Layout>
            );
          };
      
          export const query = graphql`
            query($id: String!, $title: String!) {
               markdownRemark((id: {eq: $id})  {
                 title
                 description
                 content
               }
            }
          `
      
           export default Blogs;
      

    In other words: the first approach uses a static query (via useStaticQuery hook. Static, no dynamic parameters allowed) and the second uses a page query (only available in pages or templates)