Help With GraphQuery: Repeatable Group With Content Relationships

I have a "Settings" document with a repeatable group called "Navigation." This group has one field called "Mega Menu Item." It's a content relationship that can link to Mega Menu Item documents, each of which has its own fields. Something like this:

settings: {
    navigation: [
        {
            mega_menu_item: {
                label
                url
            }
        }
    ]
}

I want to get all items in settings.navigation, and also the fields of each item's linked document. I have tried writing the GraphQuery for this, but no matter what I try, I can't get the fields. I only get the array of items in "navigation," each of which contains a single "link_type: 'Document'" field.

Here is the query I came up with:

  const response = await client.getSingle("settings", {
    graphQuery: `
      {
          navigation {
              mega_menu_item {
                  ...on mega_menu_item {
                    label
                    url
                  }
              }
          }
      }`,
  });

Please let me know what I'm doing wrong here. My goal here is to understand Prismic's GraphQuery better so that I can more easily build my own queries.

NOTE: It may look as though I could have just put "label" and "url" directly in the repeatable group, instead of linking to another document. However, my actual use case is that I need each Mega Menu Item to itself contain multiple sections. For now, though, I'm just trying to solve this issue with fetching the top level, before getting deeper into the nesting.

Hi @josh.klope,

I'll be happy to help you with this. I think you might be missing a couple of things between mega_menu_item and label/url. Would it be possible for you to share your repository name so I can get the same structure as you when I run the queries? This can be a bit finnicky, so I want to make sure I get it right! You can DM me it if you don't want to post it here, and if you'd rather keep that private, I'll investigate without, no worries :slight_smile:

Hi @josh.klope,

Thanks for the DM, I'm continuing the conversation here in case it helps any future users :slight_smile: Where is your content relationship set up exactly, in the backend?

In your API, you can see that you've got:

A good way to look at your queries is to double check your API. You won't be able to get anything more than what is just there, so the fact you're only getting "a single "link_type: 'Document'" field" makes sense! Could you share a screenshot of your Slice Machine components with the content relationship, or elaborate a little bit on how you have it set up? :slight_smile:

Thanks for your response, @Ezekiel . I realized that I actually hadn't linked any mega_menu_item documents in my repository. I took care of that, and now the response I get is different, but it still doesn't contain the fields of the linked document:

navigation: [
      {
        mega_menu_item: {
          id: 'ZyFQtxIAACcAhR61',
          type: 'mega_menu_item',
          tags: [],
          lang: 'en-us',
          slug: 'test-item-1',
          first_publication_date: '2024-10-29T21:16:42+0000',
          last_publication_date: '2024-11-04T14:36:00+0000',
          uid: 'mega-menu-item-1',
          link_type: 'Document',
          isBroken: false
        }
      },
      {
        mega_menu_item: {
          id: 'ZyFQwxIAACkAhR7P',
          type: 'mega_menu_item',
          tags: [],
          lang: 'en-us',
          slug: 'test-item-2',
          first_publication_date: '2024-10-29T21:17:27+0000',
          last_publication_date: '2024-11-04T14:36:28+0000',
          uid: 'mega-menu-item-2',
          link_type: 'Document',
          isBroken: false
        }
      }
    ]

A screenshot of my Mega Menu Item custom type:

And a screenshot of a Mega Menu Item in my repository:

As you can see, there is some nesting going on, which is why I'm using content relationships to model the mega menu data.

The query I gave in my first post must be incorrect, because I'm expecting to see the label and url fields in the response, as well as the two arrays of linked documents on each mega_menu_item, as shown in the screenshot above.

Thanks for all the information, @josh.klope!

Here's what I got working on my end:

  const settings = await client.getSingle('settings', {
    graphQuery: `
      {
        settings {
          navigation {
            mega_menu_item {
              ... on mega_menu_item {
                label
                url
              }
            }
          }
        }
      }
    `
  });

You can then get this response from settings.data.navigation (data will be an object unless you JSON.stringify it, but the data will be there):

[
  {
    "mega_menu_item": {
      "id": "ZyFQtxIAACcAhR61",
      "type": "mega_menu_item",
      "tags": [],
      "lang": "en-us",
      "slug": "item-1",
      "first_publication_date": "2024-10-29T21:16:42+0000",
      "last_publication_date": "2024-10-29T21:16:42+0000",
      "uid": "mega-menu-item-1",
      "data": {
        "label": "Item 1"
        "url": "test"
      },
      "link_type": "Document",
      "isBroken": false
    }
  },
  {
    "mega_menu_item": {
      "id": "ZyFQwxIAACkAhR7P",
      "type": "mega_menu_item",
      "tags": [],
      "lang": "en-us",
      "slug": "item-2",
      "first_publication_date": "2024-10-29T21:17:27+0000",
      "last_publication_date": "2024-10-29T21:17:27+0000",
      "uid": "mega-menu-item-2",
      "data": {
        "label": "Item 2"
        "url": "test"
      },
      "link_type": "Document",
      "isBroken": false
    }
  }
]

And from then on, you should have access to the fields you need and choose to display them however you wish. This should be reproduce-able with further nested groups, the queries might get a bit long and parsing the responses could be a little inelegant, but you'll get the data!

Additionally, if you can get the uid of the document you need with a simpler query, you can also extract that and use that fetched uid to get the information you need. For example:

const page = await client.getByUid(documentType, fetchedUID)

And then use that response as you wish.

Let me know if that works for you, and if you need any more help :slight_smile:

@Ezekiel , great, that worked for me, too. I was also able to extend the query and get all the data I needed at the deeper levels of nesting.

I can see what you mean about the inelegant parsing. TypeScript does not seem to recognize all the levels of nesting I should be getting back (for example, that mega_menu_item should have its own data object), so I will probably end up casting to "any" and then parsing with Zod. Is this the expected type behavior?

Also, do you know of a better way to get my nav bar data, considering the level of nesting? I'm going for the single query approach because the user should not have to wait for several API requests to complete sequentially just to see the nav bar.

P.S. In case it might help anyone else, below is the query that ended up working for me. In my data, the Settings model has a repeatable group called Navigation. Each item in this group is a link to a MegaMenuItem document. Each MegaMenuItem document has a Label, a URL, and a repeatable group called Sections. Each item in this group is a link to a MegaMenuSection document. Each MegaMenuSection document has a Title and a repeatable group called Links. Each item in this group is a normal Prismic link (not a content relationship).

The following query gets all of this nested data in one API request:

  const response = await client.getSingle("settings", {
    graphQuery: `
    {
      settings {
        navigation {
          mega_menu_item {
            ...on mega_menu_item {
              label
              url
              sections {
                section {
                  title
                  links
                }
              }
            }
          }
        }
      }
    }
    `,
  });

Thank you for sharing the exact query! Hope it helps someone else :slight_smile:

It is the expected type behavior, absolutely. It's also currently the best way we have to get nested data. If you'd prefer having less levels, you'd need to rethink some of the architecture of your slices/data (essentially by removing some levels), such as having a specific custom type for the navbar instead of having it inside settings. This is just an example, I don't know exactly what your use case is here, and I trust you'll know best which way to go about it!

If you're expecting to have further levels of nesting and would like to read up more on queries, or different ways to approach this, I recommend checking out these forum threads and pages, which may touch on issues/topics that will be relevant to you when you work on your project:

And if you run into any issue that hasn't been talked about, feel free to reach out as always :slight_smile: