Gatsby GraphQL for only current directory - graphql

I followed the Gatsby tutorial and ended up with a GraphQL like:
query {
allMdx(sort: {fields: frontmatter___date, order: DESC}) {
nodes {
frontmatter {
date(formatString: "MMMM D, YYYY")
title
}
id
slug
}
}
}
This gives me the expected result of:
{
"data": {
"allMdx": {
"nodes": [
{
"frontmatter": {
"date": "January 25, 2022",
"title": "Image Blog"
},
"id": "cc11f4c4-43a5-573a-9ea6-3806f7e2fc64",
"slug": "image-blog/"
},
{
"frontmatter": {
"date": "July 24, 2021",
"title": "Page B"
},
"id": "1fb36e34-d1f4-5ac2-8c18-1030733cfce1",
"slug": "b"
},
{
"frontmatter": {
"date": "July 24, 2021",
"title": "Page C"
},
"id": "2f0ed709-c7ab-5a3f-9846-1340699b4bd1",
"slug": "c"
},
{
"frontmatter": {
"date": "July 24, 2021",
"title": "Sub Page D"
},
"id": "d9cc842d-dc45-508a-8d5d-8dc1f2b0b232",
"slug": "sub/d"
},
{
"frontmatter": {
"date": "July 24, 2021",
"title": "Sub Sub Page E"
},
"id": "2005bd62-37a7-580b-9950-e1b7c3688c0b",
"slug": "sub/subsub/e"
},
{
"frontmatter": {
"date": "July 23, 2021",
"title": "Page A"
},
"id": "58dd9cf4-8e20-5602-87ef-5eb18cd74636",
"slug": "a"
}
]
}
},
"extensions": {}
}
As you can see the result contains all pages.
What I would like to achieve is to have an "index" page that only show links to the pages within the same directory of the "index" page.
How can I modify the query to return only the current directory's pages?
EDIT:
I made some progress by changing the query to:
query{
allMdx(
sort: {fields: frontmatter___date, order: DESC}
filter: {slug: {regex: "/^sub/[^/]+$/"}}
) {
nodes {
frontmatter {
date(formatString: "D MMMM YYYY")
title
}
id
slug
}
}
}
which gives the result of:
{
"data": {
"allMdx": {
"nodes": [
{
"frontmatter": {
"date": "24 July 2021",
"title": "Sub Page D"
},
"id": "4de57b7f-5e87-520f-ab06-940fb6f91340",
"slug": "sub/d"
}
]
}
},
"extensions": {}
}
But my graphQL is hard-coded. I still do not understand how to pass in a variable dynamically so that it would give different results depending on which slug/directory the page was loaded, for example to have something like:
filter: {slug: {regex: $expression}}
This is the full page code I have so far:
import * as React from 'react'
import { Link, graphql } from 'gatsby'
import Layout from '../../components/layout'
const BlogPage = ({ data, location }) => {
//const slug = location.pathname;
return (
<Layout pageTitle="My Blog Posts">
{
data.allMdx.nodes.map(node => (
<article key={node.id}>
<h2>
<Link to={`/blog/${node.slug}`}>
{node.frontmatter.title}
</Link>
</h2>
<p>Posted: {node.frontmatter.date}</p>
</article>
))
}
</Layout>
)
}
export const query = graphql`
query{
allMdx(
sort: {fields: frontmatter___date, order: DESC}
filter: {slug: {regex: "/^sub/[^/]+$/"}}
) {
nodes {
frontmatter {
date(formatString: "D MMMM YYYY")
title
}
id
slug
}
}
}
`
export default BlogPage

Your query is fetching all data from the MDX (hence the allMdx node), set in the gatsby-source-filesystem so it's getting all title and date from frontmatter, without filtering.
One easy thing that is the straightforward workaround in this scenarios of filtering desired pages is adding a key field in your MDX files so you can filter your query using that field:
query {
allMdx(
filter: {frontmatter: { key: { eq: "index-page"}}}
sort: {fields: frontmatter___date, order: DESC}) {
nodes {
frontmatter {
date(formatString: "MMMM D, YYYY")
title
}
id
slug
}
}
}
So you will be only fetching one-page data.

Related

Apollo is not letting me edit an object field because it is readonly, but I cannot just make a copy of it

I am not sure how I should set cart.items to a new array, I have already made a copy of the original cache because I learned Apollo does not let you directly edit the cache, but I am still getting the following error
Error: Cannot assign to read only property 'items' of object '#'
Do I need to make a copy of the items array? And if so how do I go about changing the array on the current objects item field?
Here are my console.logs
You can ignore the typename fields as they are irrelevant to the problem
addItem
{
"__typename": "Cart",
"items": [
{
"__typename": "CartItem",
"name": "Item 3"
},
{
"__typename": "CartItem",
"name": "Item 4"
},
{
"__typename": "CartItem",
"name": "New Item!"
}
]
}
carts
{
"carts": [
{
"__typename": "Cart",
"id": "1",
"items": [
{
"__typename": "CartItem",
"id": "1",
"name": "Item 1"
},
{
"__typename": "CartItem",
"id": "2",
"name": "Item 2"
}
]
},
{
"__typename": "Cart",
"id": "2",
"items": [
{
"__typename": "CartItem",
"id": "3",
"name": "Item 3"
},
{
"__typename": "CartItem",
"id": "4",
"name": "Item 4"
}
]
}
]
}
So it seems you need to remake the items array as well since items is its own gql object type the easiest way to do this was to do it all at once with a map.
Please note the comment as that was an important detail I learned
// IMPORTANT NOTE when updating the cache of a query you must return the
// same fields as the original query even if you aren't using them in the code
const GET_CARTS = gql`
query {
carts{
id
items{
id
name
}}} `;
const MUTATION = gql`
mutation AddItem($input:MutationAddItemInput!) {
addItem(input: $input){
items{
id
name
}
}
}
`;
const { loading, error, data } = useQuery(GET_CARTS)
const [addItem] = useMutation(MUTATION, {
// refetchQueries: [{ query: GET_CARTS }]
update(cache, { data: { addItem } }) {
// addItem is the response of the query of add item function
console.log({ addItem });
// #ts-ignore
let { carts } = cache.readQuery({ query: GET_CARTS });
console.log({ carts })
// make a new array out of the carts array and add the new item to the array if the id of the cart is 2
let newCarts = carts.map((cart: Cart) => {
if (cart.id === "2") {
return { ...cart, items: [...addItem.items] }
} else {
return cart
}
})
console.log({ newCarts });
cache.writeQuery({
query: GET_CARTS,
data: { carts: newCarts }
// data: { carts: [{ id: "1", items: [{ id: "2", name: "an item" }] }] }
})
}
})
And lastly you will call the addItem function from the use mutation hook

GraphQL query limiting tag count

This is GraphQL query from the gatsby project:
const Data = useStaticQuery(graphql`
query {
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
limit: 5
) {
edges {
node {
excerpt(pruneLength: 300)
fields {
slug
}
frontmatter {
date(formatString: "DD [<span>] MMM [</span>]")
title
description
tags
}
}
}
group(field: frontmatter___tags) {
totalCount
fieldValue
}
}
}
`);
const Posts = Data.allMarkdownRemark.edges;
const Tags = Data.allMarkdownRemark.group;
The above code is used to show the latest 5 posts and all the tags (including count of each tag). The problem is after showing 5 latest posts it only shows tag count of 5.
If I apply limit of 2000 to the group section as shown below, I get error while doing gatsby develop.
group(field: frontmatter___tags, limit: 2000)
Here is my GraphQL IDE output for the query:
{
allMarkdownRemark(sort: {fields: id}) {
group(field: frontmatter___tags) {
totalCount
fieldValue
}
}
}
output:
{
"data": {
"allMarkdownRemark": {
"group": [
{
"totalCount": 27,
"fieldValue": "android"
},
{
"totalCount": 24,
"fieldValue": "c"
},
{
"totalCount": 42,
"fieldValue": "chash"
},
{
"totalCount": 31,
"fieldValue": "cplus"
},
{
"totalCount": 36,
"fieldValue": "css"
},
{
"totalCount": 22,
"fieldValue": "html"
},
{
"totalCount": 24,
"fieldValue": "html5"
},
{
"totalCount": 30,
"fieldValue": "java"
},
{
"totalCount": 11,
"fieldValue": "jsp"
},
{
"totalCount": 18,
"fieldValue": "mysql"
},
{
"totalCount": 37,
"fieldValue": "networking"
},
{
"totalCount": 33,
"fieldValue": "php"
},
{
"totalCount": 8,
"fieldValue": "xml"
}
]
}
},
"extensions": {}
}
Somehow the limit of 5 for latest posts is getting applied to the count of tags to be displayed.
In that case, run multiple queries by giving each one an alias.
Here is an example:
const Data = useStaticQuery(graphql`
query {
posts: allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
limit: 5
) {
edges {
node {
excerpt(pruneLength: 300)
fields {
slug
}
frontmatter {
date(formatString: "DD [<span>] MMM [</span>]")
title
description
tags
}
}
}
}
tags: allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
group(field: frontmatter___tags) {
totalCount
fieldValue
}
}
}
`);
const Posts = Data.posts.edges;
const Tags = Data.tags.group;

Get GraphQL output without second curly bracket

I have a problem. I do not want a "break" down in my GraphQL output. I have a GraphQL schema with a person. That person can have one or more interests. But unfortunately I only get a breakdown
What I mean by breakdown is the second curly brackets.
{
...
{
...
}
}
Is there an option to get the id of the person plus the id of the interests and the status without the second curly bracket?
GraphQL schema
Person
└── Interest
Query
query {
model {
allPersons{
id
name
interest {
id
status
}
}
}
}
[OUT]
{
"data": {
"model": {
"allPersons": [
{
"id": "01",
"name": "Max",
"interest ": {
"id": 4488448
"status": "active"
}
},
{
"id": "02",
"name": "Sophie",
"interest ": {
"id": 15445
"status": "deactivated"
}
},
What I want
{
{
"id": "01",
"id-interest": 4488448
"status": "active"
},
{
"id": "02",
"name": "Sophie",
"id-interest": 15445
"status": "deactivated"
},
}
What I tried but that deliver me the same result
fragment InterestTask on Interest {
id
status
}
query {
model {
allPersons{
id
interest {
...InterestTask
}
}
}
}

How to mutate a list of objects in an array as an argument in GraphQL completely

I cannot mutate a list of objects completely, because only the last element of the array will be mutated.
What already works perfectly is, if I put each element ({play_positions_id: ...}) in the array manually like here:
mutation CreateProfile {
__typename
create_profiles_item(data: {status: "draft", play_positions: [{play_positions_id: {id: "1"}}, {play_positions_id: {id: "2"}}]}) {
id
status
play_positions {
play_positions_id {
abbreviation
name
}
}
}
}
Output:
{
"data": {
"__typename": "Mutation",
"create_profiles_item": {
"id": "1337",
"status": "draft",
"play_positions": [
{
"play_positions_id": {
"id": "1",
"abbreviation": "RWB",
"name": "Right Wingback"
}
},
{
"play_positions_id": {
"id": "2",
"abbreviation": "CAM",
"name": "Central Attacking Midfielder"
}
}
],
}
}
}
Since you can add many of those elements, I defined a variable/argument like here
mutation CreateProfile2($cpppi: [create_profiles_play_positions_input]) {
__typename
create_profiles_item(data: {status: "draft", play_positions: $cpppi}) {
id
status
play_positions {
play_positions_id {
id
abbreviation
name
}
}
}
}
Variable object for above:
"cpppi": {
"play_positions_id": {
"id": "1"
},
"play_positions_id": {
"id": "2
}
}
Output:
{
"data": {
"__typename": "Mutation",
"create_profiles_item": {
"id": "1338",
"play_positions": [
{
"play_positions_id": {
"id": "2",
"abbreviation": "CAM",
"name": "Central Attacking Midfielder"
}
}
],
}
}
}
Schema:
input create_profiles_input {
id: ID
status: String!
play_positions: [create_profiles_play_positions_input]
}
input create_profiles_play_positions_input {
id: ID
play_positions_id: create_play_positions_input
}
input create_play_positions_input {
id: ID
abbreviation: String
name: String
}
At the last both snippets, only the last object with the id "2" will be mutated. I need these to use the defined input type from my backend.
I figured it out. I got it wrong with the brackets in the variable. Here the solution:
"cpppi": [
{
"play_positions_id": {
"id": "1"
}
},
{
"play_positions_id": {
"id": "2"
}
}
]

Incorrectly selected data in the query

Only articles that contain the EmailMarketing tag are needed.
I'm probably doing the wrong search on the tag, since it's an array of values, not a single object, but I don't know how to do it right, I'm just learning graphql. Any help would be appreciated
query:
query {
enArticles {
title
previewText
tags(where: {name: "EmailMarketing"}){
name
}
}
}
result:
{
"data": {
"enArticles": [
{
"title": "title1",
"previewText": "previewText1",
"tags": [
{
"name": "EmailMarketing"
},
{
"name": "Personalization"
},
{
"name": "Advertising_campaign"
}
]
},
{
"title": "title2",
"previewText": "previewText2",
"tags": [
{
"name": "Marketing_strategy"
},
{
"name": "Marketing"
},
{
"name": "Marketing_campaign"
}
]
},
{
"title": "article 12",
"previewText": "article12",
"tags": []
}
]
}
}
I believe you first need to have coded an equality operator within your GraphQL schema. There's a good explanation of that here.
Once you add an equality operator - say, for example _eq - you can use it something like this:
query {
enArticles {
title
previewText
tags(where: {name: {_eq: "EmailMarketing"}}){
name
}
}
}
Specifically, you would need to create a filter and resolver.
The example here may help.

Resources