6

I have a dataset with posts, which might have an array of categories.

How do I make a GROQ query that selects all posts with a category with the title "Page"?

I would think that I could do something like this:

*[_type == 'post' && categories[]->title == 'Page']{
  body,
  slug,
}

I probably need to use function for matching inside an array but the cheetsheet is too dense for me - I just can't find it.

The gist of my dataset is:

{
  {
    _createdAt: "2018-08-24T17:59:04Z",
    _id: "e84d78f0-81ed-4524-9c36-f38a1f1b2375",
    _rev: "1X9D03Y03BUslZ33alDJwF",
    _type: "category",
    _updatedAt: "2018-08-24T18:13:14Z",
    description: "Pages/Sider",
    title: "Page"
  },
  {
    _createdAt: "2018-08-26T21:57:54Z",
    _id: "3c023e29-b167-4021-be00-5e8dc14f65cc",
    _rev: "WQjjTjyYBRudo6JCOBCUj7",
    _type: "post",
    body: [
      {}
    ],
    categories: [],
  },
  {
    _createdAt: "2018-08-24T17:57:55Z",
    _id: "3d8f0c40-a45d-4dc7-ad95-ed1b49bca4af",
    _rev: "WQjjTjyYBRudo6JCO0spXR",
    _type: "post",
    body: [
      {}
    ],
    categories: [
      {
        _key: "491c03573205",
        _ref: "e84d78f0-81ed-4524-9c36-f38a1f1b2375",
        _type: "reference"
      }
    ]
  }
}

A simple query:

*[_type == 'post']{
  //  body,
  "category": categories[]->title,
  //  slug,
  categories
}

Returns:

{
  categories: [],
  category: []
}

{
  categories: [
    {
      _key: "491c03573205",
      _ref: "e84d78f0-81ed-4524-9c36-f38a1f1b2375",
      _type: "reference"
    }
  ],
  category: [
    Page
  ]
}
dotnetCarpenter
  • 10,019
  • 6
  • 32
  • 54

1 Answers1

6

As per the join documentation you can use inner joins in a GROQ filter. I think this should work for you, provided that your category-documents are _type: "category" :

*[_type == 'post' &&
  *[_type == "category" &&
    title == "Page"][0]._id in categories[]._ref]{
   body,
   slug,
 }

Hope this solves your problem!

Benzara Tahar
  • 2,058
  • 1
  • 17
  • 21
knut
  • 371
  • 1
  • 6
  • 1
    Thanks! I just need to grok the following in GROQ: When you say `[condition][0]` to choose a post with "category" and `title == "page"`, are you checking only the first object in `categories[]` or is it the first item in the array that the `in` operator returns? I'm confused to how GROQ handles arrays. It looks like you can just notate that it's an array and then write the query as it is not and GROQ will iterate your selector on each item in the array. And then again sometimes you have to be very specific and say, _"I want the first or nth index of the array". – dotnetCarpenter Aug 27 '18 at 14:44
  • 1
    @kmeive Can you elaborate on the filter going into the inner join in your answer? Especially `*[...][0]._id in`. – dotnetCarpenter Aug 27 '18 at 14:47
  • 1
    `*[condition][0]` will get the first item in the array which is returned by `*[conidtion]`. This is because as for now, the `in` operator just works with a string on the left side. We don't (yet) have an operator for doing an intersection of arrays I'm afraid. I figured it would work in your specific case beacuse the logic was that you wanted posts that had _a_ category with the title "page" in them. – knut Aug 28 '18 at 15:58
  • 1
    Just to confirm that I understand your answer, I will check this with you. `*[_type == "category" && title == "Page"]` will return an array of all published categories and since we have only one that is called Page, we can safely take the first index 0 and use the id to check all of the `_type == 'post'` have `_id == categories[]._ref`? – dotnetCarpenter Aug 28 '18 at 19:27
  • 1
    A follow up question (maybe I should create another question here but bare with me): I've created a demo here: https://www.skovbar.dk/ It calls sanity with your query and writes the number of pages. _Antal sider udgivet i sanity: [number of pages from sanity]_. It's deployed on google CDN, just as sanity data. When I open devtools I don't see any requests to sanity at all! How does it work?!? It's pure magic ;) – dotnetCarpenter Aug 28 '18 at 19:31
  • 1
    It certainly feels a bit like magic, but it's due to Nuxt’s way of handling data fetching in the `async data` method. On the first request, it does the fetching and the rendering serverside, and on the subsequent on the client side. E.g if you make another page with data from Sanity, and use the `` component to navigate between them, you will observe API calls in the browser too. So that magic is to Nuxt’s credit :) [Read more about it here](https://nuxtjs.org/guide/async-data) – knut Aug 29 '18 at 04:41