How do you access the custom tags in a query?

I've set up the custom tags per the post here, but I can't figure out how to query each category individually. I have a few custom categories listed: ['light', 'color', ...] - How would I go about grabbing all linked documents of that type? I'm trying to build groups where I iterate over the results, but I can't seem to get anything other than a huge list, and I'd have to destructure the heck out of it to be able to iterate. I'm sure there's a way to query it and I just don't know it yet. Thanks!

Something like:

Prismic.Predicates.at('document.type', 'category'), Prismic.Predicates.has('my.category.uid', 'light')

Hey Mark,

Do you want to query all of the categories that are linked on a document? If that's the case, you might want to use fetchLinks.

Or, do you want to query all of the documents that link to a category? If that's the case, you might be looking for a "query by content relationship."

Also, let me know what technology you're using. Then, I can get the appropriate documentation for you :slight_smile:

Best,
Sam

I'm trying to use it to get all documents that have a specific category custom type.

[ color, light, transitions, sfx, ...] So instead of a giant list of all documents, I want to separate them by category so I can style them differently and use them as different routes in Nextjs (e.g. /shop/[category].js and /shop/[category]/[uid])

So if you go to /shop/texthere, it will see if any routes have been populated by category, and if you go one deeper (/shop/text/moretext), it'll target the actual product.

My original thought was to query all documents, and then subquery all documents that have a 'my.product.category.uid' of whatever the string category is.

Something like as follows:

client.query([Prismic.Predicates.at('document.type', 'product'),
  Prismic.Predicates.has('my.product.category.uid', categoryVar)])

Hey @mark ,

It sounds like you're looking for "Query by Content Relationship." Here's the docs for how to do that with JavaScript:

Let me know if you have any questions about it!

Sam

But I'd have to specify the ID, correct? So for every query I'd have to first grab the id? How does that flow work? Here are the queries I'm looking for:

  1. ALL products in every category
  2. ALL products that have a 'category' Custom Type set to 'light'
  3. ALL products that have a 'category' Custom Type set to 'sfx'
    ...

Are you saying I need to first query by UID to get the document id, and then query by content relationship using the ID? It says you can't use UID, and the ID is the randomly generated number, yes?

Hey @mark ,

This depends on your app architecture. If, you have this page:

example.com/category/light

Then, yes, you will need to perform two queries (this is pseudo javascript):

const { id } = await client.queryByUID('category', route.category) // route.category is a stand-in for however you access your route params
const products = await client.query('my.document.category', id)

The Prismic CDN is highly optimized, and the average response time for a cached result on the CDN is around 25ms, so the second query should be virtually unnoticeable.

Alternatively, if you include the ID in your route, you could make one query:

example.com/category/light/135asd

And:

const products = await client.query('my.document.category', route.category)

If you're not worried about routing, this might be much more simple. For example, if you have a list of recent posts by ID on the homepage, then you can include a Content Relationship field on your homepage Custom Type, which will give you the ID.

This also works as a compliment to routing. Say you have a nav menu document, you model the links in the nav menu with Content Relationship fields, which will — again — give you direct access to the ID that you need to generate the route (which you can do programmatically with a Link Resolver.)

Sorry if this is too much information, unclear information, or irrelevant to your use case. I'm just trying to cover all of the bases! But let me know if it's helpful, or if you have further questions. I'm happy to throw together an example for your use case if that would help.

Best,
Sam

Here is the structure I'm talking about. It's a descendant structure.

All products > category > individual product. So /shop is all products, /shop/light is all products that are of the 'light' category, and /shop/light/product-1 is the individual product UID (which is product-1 in this case).

I can't seem to get all products that match a given category. I need an array of them. It wouldn't make sense to query them all individually.

I have it this way because of the Nextjs structure, I want the 'url' of the pages to be the UID (which is human readable/typeable) rather than the ID (which is a random mess of numbers and letters).

Hi @mark ,

It sounds like we can break this down into a few steps.

In Next.js, you would include these pages:

src/
└── pages/
    └── [category]/
        ├── index.js
        └── [product].js

So we're discussing src/pages/[category]/index.js and src/pages/[category]/[product].js, but for the sake of brevity I'm going to call these files [category]/index.js and [category]/[product].js.

There are three steps for creating your routes:

Step One: Querying for a category page

So, [category]/index.js is your category page. On this page, you'll use the "Query by Content Relationship" that I described above to get an array of all of the products of a given category. That's where you'll use code that looks like this:

const { id } = await client.queryByUID('category', route.category) // route.category is a stand-in for however you access your route params
const products = await client.query('my.document.category', id)

So, when a user navigates to /category/light, you will query all of the "light" documents, receive an array, and render it.

Step Two: Querying for a product page

For this step, the setup is straightforward, but you can add more rigidity for more structured routing.

Basic

You can use a standard queryByUID using the product variable from your dynamic route. Because the product UIDs are unique, you will get the correct document without needing to worry about the category, and the route will work fine.

More rigid

The problem is that any [category] route segment will work. So, /dogs/poodle will render the poodle document, but so will /cats/poodle or /foobar/poodle.

If you want to guard against that, you can add a client-side check to double check the UID of the category. The document that you get back will have a property document.data.category.uid. You can check if document.data.category.uid matches router.query.category (the category route segment). If it doesn't match, you can forward to a 404 instead of rendering.

Step 3: Create a route resolver

For a nested route, we recommend using a route resolver. It gives you lots of control over how to construct your internal links. The Route Resolver is available as a config option in Nuxt.js and Next.js projects and as an API option for all other projects — though the fundamental syntax is the same everywhere. For you, it would look something like this:

{
  type: 'product',
  path: '/:category/:uid',
  resolvers: {
    category: 'category' // id of the content relationship in the article mask
  }
}

Here's the documentation for the Route Resolver in Next.js.

With the Route Resolver in place, the Prismic helpers — like Prismic's <RichText/> and <Link/> components — will construct links using the category and product UID.


I hope this is helpful! I realize that it's more detail than you asked for, but I just wanted to make sure I didn't miss anything. Please let me know if this is helpful. If not, I'm happy to keep helping with troubleshooting and debugging.

Sam

That's crazy. I was able to figure out the query part last night, and it almost exactly mirrors what you're doing. Awesome!

I'm still not entirely up to speed on the resolver. My sm-resolver has been auto-generated a few times, and it looks nothing like what is shown.

This is my auto-generated sm-resolver:

import { Fragment } from 'react'

import * as Slices from './slices'

import { Slices as EssentialSlices } from 'essential-slices'

const __allSlices = {  ...EssentialSlices, ...Slices, }

const NotFound = ({ sliceName, slice, i }) => {

  console.error(`[sm-resolver] component "${sliceName}" not found at index ${i}.`)

  console.warn(`slice data: ${slice}`)

  return process.env.NODE_ENV !== 'production' ? (

    <div

      style={{

        height: '30vh',

        display: 'flex',

        alignItems: 'center',

        justifyContent: 'center',

        flexDirection: 'column',

        textAlign: 'center',

        background: '#FAFAFA'

      }}

    >

      <h2>

        Slice "{sliceName}" not found.

      </h2>

      <p style={{ maxWidth: '320px', fontSize: '16px' }}>

        Check that you registered this component in your slices library!

      </p>

    </div>

  ) : <Fragment />

}

export default function SliceResolver({ sliceName, ...rest }) {

  return __allSlices[sliceName] ? __allSlices[sliceName] : () => <NotFound sliceName={sliceName} {...rest} />

}

I believe I have everything set up the way I need except for the slicezone. Keep in mind that my setup looks nothing like what I'm seeing in the docs, and I'm not sure where the deviation happened, but it's nearly impossible to troubleshoot. I'm more than happy to push a version of this codebase to a public repo so you can take a look if needed.

Thanks for the assist!

I should also clarify, that in order to make the structure of the routing more rigid, I used next's folder/file nesting to accomplish what I'm trying to get no /dog/poodle - /cat/poodle issues:

I have /shop > [category] > [uid], where in my static paths, I'm passing both category and uid params to the staticprops method.

Hey @mark ,

The Route Resolver and the sm-resolver are two different things. The Route Resolver constructs URLs for your documents. sm-resolver matches Slice Components with Slice Content.

Does that clarify what's happening in your project?

Sam

This thread has been closed due to inactivity. Flag to reopen.