Is it possible to use dynamic query alias names in GraphQL? - graphql

I am currently working on a Gatsby documentation site. One particular page retrieves the content of various README files for HTML/CSS components which are grouped into three different categories, based on regex searches of their local filepath structure. I'm using 3 separate aliased queries at the moment to retrieve very similar data and the DRY coder in me feels this should be possible with one and a $group-type variable (which would replace atoms, molecules and organisms in the below code) or something similar. As I'm a real newbie to GraphQL I'm not sure if this is possible and I can't seem to find anyone doing this online. Here's what I have so far:
export const pageQuery = graphql`
query($path: String!) {
pageData:
markdownRemark(fields: { slug: { eq: $path } }) {
html
fields {
slug
title
}
fileAbsolutePath
}
atoms:
allMarkdownRemark(sort: {order: ASC, fields: [fields___title]}, limit: 1000, filter: {fileAbsolutePath: {regex: "/dl-atoms/"}}) {
edges {
node {
fields {
slug
title
}
}
}
}
molecules:
allMarkdownRemark(sort: {order: ASC, fields: [fields___title]}, limit: 1000, filter: {fileAbsolutePath: {regex: "/dl-molecules/"}}) {
edges {
node {
fields {
slug
title
}
}
}
}
organisms:
allMarkdownRemark(sort: {order: ASC, fields: [fields___title]}, limit: 1000, filter: {fileAbsolutePath: {regex: "/dl-organisms/"}}) {
edges {
node {
fields {
slug
title
}
}
}
}
}
`;

You can define fragments to use in your queries. These allow you to define a selection set once and then use it just by referencing the name of the fragment. Do note that you have to know the name of the type for which you're specifying the selection set.
export const pageQuery = graphql`
query($path: String!) {
pageData:
markdownRemark(fields: { slug: { eq: $path } }) {
html
fields {
slug
title
}
fileAbsolutePath
}
atoms:
allMarkdownRemark(sort: {order: ASC, fields: [fields___title]}, limit: 1000, filter: {fileAbsolutePath: {regex: "/dl-atoms/"}}) {
...MarkdownRemarkFields
}
molecules:
allMarkdownRemark(sort: {order: ASC, fields: [fields___title]}, limit: 1000, filter: {fileAbsolutePath: {regex: "/dl-molecules/"}}) {
...MarkdownRemarkFields
}
organisms:
allMarkdownRemark(sort: {order: ASC, fields: [fields___title]}, limit: 1000, filter: {fileAbsolutePath: {regex: "/dl-organisms/"}}) {
...MarkdownRemarkFields
}
}
fragment MarkdownRemarkFields on MarkdownRemarkConnection {
edges {
node {
fields {
slug
title
}
}
}
}
`;
Fragments are mentioned in the Gatsby docs here.

Related

Gatsby GraphQL query no longer working after update

So I had this graphql query on my gatsby site before they updated and now it no longer works.
query ($skip: Int!, $limit: Int!) {
allMdx(
filter: { fileAbsolutePath: { regex: "/posts/" } }
sort: { order: DESC, fields: frontmatter___date }
skip: $skip
limit: $limit
) {
nodes {
id
frontmatter {
alt
title
path
slug
date(formatString: "MMMM Do, YYYY")
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
It says "fileAbsolutePath" is not defined by type mdxfilterinput
I don't know what other way to update this to make it show my data again because the other options don't make sense
What would I use in replace of fileabsolutepath for my graph ql query to work again with the new updated gatsby version?

Getting error Field "cover" must not have a selection since type "String" has no subfields when deploy

I am getting error when deploy on netlify:
10:49:33 AM: error There was an error in your GraphQL query: 10:49:33
AM: Field "cover" must not have a selection since type "String" has no
subfields. 10:49:33 AM: This can happen if you e.g. accidentally added
{ } to the field "cover". If you didn't expect "cover" to be of type
"String" make sure that your input source and/or plugin is correct.
failed extract queries from components - 0.355s
Here is my following code:
export const pageQuery = graphql`
{
hero: allMarkdownRemark(filter: { fileAbsolutePath: { regex: "/hero/" } }) {
edges {
node {
frontmatter {
title
name
subtitle
buttonText
}
html
}
}
}
about: allMarkdownRemark(filter: { fileAbsolutePath: { regex: "/about/" } }) {
edges {
node {
frontmatter {
title
avatar {
childImageSharp {
fluid(maxWidth: 700, quality: 90, traceSVG: { color: "#64ffda" }) {
...GatsbyImageSharpFluid_withWebp_tracedSVG
base64
}
}
}
skills
}
html
}
}
}
jobs: allMarkdownRemark(
filter: { fileAbsolutePath: { regex: "/jobs/" } }
sort: { fields: [frontmatter___date], order: DESC }
) {
edges {
node {
frontmatter {
title
company
location
range
url
}
html
}
}
}
featured: allMarkdownRemark(
filter: { fileAbsolutePath: { regex: "/featured/" } }
sort: { fields: [frontmatter___date], order: DESC }
) {
edges {
node {
frontmatter {
title
cover {
childImageSharp {
fluid(maxWidth: 700, quality: 90, traceSVG: { color: "#64ffda" }) {
...GatsbyImageSharpFluid_withWebp_tracedSVG
base64
}
}
}
tech
github
external
}
html
}
}
}
projects: allMarkdownRemark(
filter: {
fileAbsolutePath: { regex: "/projects/" }
frontmatter: { showInProjects: { ne: false } }
}
sort: { fields: [frontmatter___date], order: DESC }
) {
edges {
node {
frontmatter {
title
tech
github
external
}
html
}
}
}
contact: allMarkdownRemark(filter: { fileAbsolutePath: { regex: "/contact/" } }) {
edges {
node {
frontmatter {
title
buttonText
}
html
}
}
}
}
`;
I tried to add base64 like people said when I try to search for a solution but it still giving me this error. How can I fix it?
frontmatter {
title
cover {
childImageSharp {
fluid(maxWidth: 700, quality: 90, traceSVG: { color: "#64ffda" }) {
...GatsbyImageSharpFluid_withWebp_tracedSVG
base64
}
}
}
tech
github
external
}
In this code snippet the field cover is of String type, not an object. In graphql you can not sub select for primitive data types like int, string, id, etc. So you can not access childImageSharp in cover. Check the structure of API or fix it from the back-end. Here,
frontmatter {
title
cover
tech
github
external
}
this will work

Gatsby & Graphql: Filter allMarkdownRemark for pages matching a variable

I'm trying to filter all my markdown pages, for pages which match a certain category(specified in markdown frontmatter) and pages which are not the pages being currently visited. All pages created from markdown though are receiving the same result for allMarkdownRemark though and are not filtering any results.
I would like to know how to get all the pages to not have the same result for allMarkdownRemark, and would like the results in allMarkdownRemark to be filtered
My page query looks something like
export const pageQuery = graphql`
query ArticleQuery($path: String, $category: String, $title: String) {
allMarkdownRemark(
filter: {
frontmatter: {
category: {eq: $category},
title: {ne: $title}
}
},
sort: {
order: DESC, fields: [frontmatter___date]
}
) {
...
And my gatsby-node.js looks like
const { createFilePath } = require(`gatsby-source-filesystem`);
const { fmImagesToRelative } = require('gatsby-remark-relative-images-v2');
const path = require("path");
exports.createPages = async ({ actions: { createPage }, graphql }) => {
const postTemplate = path.resolve(`src/components/ArticlePage.jsx`);
const result = await graphql(`
{
allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___title] }
) {
edges {
node {
fields {
slug
}
frontmatter {
category
title
}
}
}
}
}
`);
if (result.errors) {
return Promise.reject(result.errors);
};
result.data.allMarkdownRemark.edges.forEach(({ node }) => {
createPage({
path: `${node.fields.slug}`,
category: `${node.frontmatter.category}`,
title: `${node.frontmatter.title}`,
component: postTemplate,
context: {node}
});
});
};
exports.onCreateNode = ({ node, getNode, actions }) => {
fmImagesToRelative(node);
if (node.internal.type === `MarkdownRemark`){
actions.createNodeField({
node,
name: `slug`,
value: createFilePath({ node, getNode, basePath: `pages`, trailingSlash: true }),
});
}
};
All markdown files include something like this in them
---
title: "My title"
category: "My category"
---
I would like to know how to get all the pages to not have the same
result for allMarkdownRemark, and would like the results in
allMarkdownRemark to be filtered
In these cases, what is commonly used is a key field for all kind of markdown files that you want to group. As you said, allMarkdownRemark is a schema inferred by Gatsby (and their transformers and sharps) at the time that you allow it to access to your filesystem so you can't distinguish directly the type of markdown. This is the simplest, cleanest, and less invasive option. You just need to:
---
title: "My title"
category: "My category"
key: "pageTypeOne"
---
Then, in your queries, you just need to filter for key field when needed:
export const pageQuery = graphql`
query ArticleQuery($path: String, $category: String, $title: String) {
allMarkdownRemark(
filter: {
frontmatter: {
category: {eq: $category},
title: {ne: $title}
key: {eq: "pageTypeOne" }
}
},
sort: {
order: DESC, fields: [frontmatter___date]
}
) {
...
You can change the string-based approach to a context one if needed in your createPage API in your gatsby-node.js. Or, depending on your needs, create a filtered query in your gatsby-node.js, creating different queries for each page, in that way your markdownRemark will be filtered already.
Alternatively, you can add different filesystems (gatsby-source-filesystem) and use the inferred sourceInstanceName to get your data:
{
resolve: `gatsby-source-filesystem`,
options: {
name: `pages`,
path: `${__dirname}/src/pages/`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts/`,
},
},
Then:
{
allFile(filter: { sourceInstanceName: { eq: "posts" } }) {
edges {
node {
extension
dir
modifiedTime
}
}
}
}

GraphQL filtering/sorting DatoCMS GatsbyJS

I have the following GraphQL query:
export const query = graphql`
query NewsQuery($slug: String!) {
datoCmsNews(slug: { eq: $slug }) {
id
title
description
slug
meta {
publishedAt
}
cover {
fluid(maxHeight: 530) {
...GatsbyDatoCmsSizes
}
}
}
allDatoCmsNews(sort: { fields: [meta___publishedAt], order: DESC }, limit: 4) {
edges {
node {
id
title
slug
meta {
publishedAt
isValid
status
}
cover {
fluid(maxHeight: 375) {
...GatsbyDatoCmsSizes
}
}
}
}
}
}
`;
On my allDatoCmsNews query how would I go about about sorting/filtering out a News item where a $slug is equal to the current slug? I don't want to show a News item if that news item is currently being viewed. I'm guessing I would have to use neq just struggling with the correct syntax.
Thanks
Pretty trivial using filter:
allDatoCmsNews(sort: { fields: [meta___publishedAt], order: DESC }, limit: 4, filter: {slug: {ne: $slug}})

Sorting GraphQL query on multiple queries in Gatsby

I'm using Gatsby as my static generator and Contentful as my datasource.
We've got multiple contentTypes in Contentful (blog, event, whitepaper) and I want to return these in within one query and sorted by createdAt date. So far I have the following which returns each contentType in order of each contentType but not in order of date overall.
Is there a way I can do a sort across the entire query?
{
whitepapers: allContentfulWhitepaper(sort: { order: DESC, fields: createdAt }) {
edges {
node {
id
slug
title
}
}
}
blogs: allContentfulBlogPost(sort: { order: DESC, fields: createdAt }) {
edges {
node {
id
slug
title
}
}
}
events: allContentfulEventPage(sort: { order: DESC, fields: createdAt }) {
edges {
node {
id
slug
title
}
}
}
}
I don't think GraphQL query is able to do the sorting across multiple fields, but you can sort in component
import React from 'react';
import { graphql } from 'gatsby';
const IndexPage = ({ data }) => {
const { whitepapers, blogs, events } = data;
const allDataInDesc = [
...whitepagers.edges.map(e => e.node),
...blogs.edges.map(e => e.node),
...events.edges.map(e => e.node),
].sort((a, b) => { return new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1; });
return <>...</>
}
export const query = graphql`
{
whitepapers: allContentfulWhitepaper(sort: { order: DESC, fields: createdAt }) {
edges {
node {
id
slug
title
createdAt
}
}
}
blogs: allContentfulBlogPost(sort: { order: DESC, fields: createdAt }) {
edges {
node {
id
slug
title
createdAt
}
}
}
events: allContentfulEventPage(sort: { order: DESC, fields: createdAt }) {
edges {
node {
id
slug
title
createdAt
}
}
}
}
`;
export default IndexPage;
Sure you can sort by multiple fields. Just pass fields and sort order as an array to your query:
query MyQuery {
allContentfulPost(
sort: { fields: [featured, updatedAt], order: [ASC, DESC] }) {
edges {
node {
featured
updatedAt(formatString: "d MM yyyy")
}
}
}
}

Resources