GROQ Syntax Error: Conditional Field Selection for Multiple Document Types

12 replies
Last updated: Aug 16, 2022
Might be a silly question, but what am I doing wrong here?
{
  "error": {
    "description": "expected '}' following object body",
    "end": 65,
    "query": "*[_type in ["banner", "footer"]] { _type == "footer" => { ... } }",
    "start": 40,
    "type": "queryParseError"
  }
}
All I'm trying to do is fetch multiple documents in a single query, while being able to define the fields for each
AI Update

Not silly at all! This is a common syntax issue with conditional projections in GROQ. The problem is that you're trying to use a conditional projection syntax that doesn't exist in GROQ.

The syntax { _type == "footer" => { ... } } isn't valid GROQ. What you're looking for is to use conditional projections inside the main projection object, not nested in another set of curly braces.

Here's the correct approach:

*[_type in ["banner", "footer"]] {
  _type,
  _type == "footer" => {
    footerField1,
    footerField2
  },
  _type == "banner" => {
    bannerField1,
    bannerField2
  }
}

The key difference from your original query is that the conditional (_type == "footer" =>) should be inside the main projection object as a direct property, not wrapped in extra curly braces.

According to the GROQ pipeline components documentation, the conditional projection syntax condition => {} expands the object on the right-hand side into the projection when the condition evaluates to true. This syntax is exactly equivalent to ...select(condition => {}).

So when you write:

{
  _type == "footer" => {
    footerField1,
    footerField2
  }
}

GROQ evaluates the condition and if it's true, it expands those fields into the main projection object.

The error "expected '}' following object body" happened because GROQ saw your nested { ... } structure and got confused about where the projection object ended. The conditional operator => creates a conditional field directly, without needing the extra wrapper braces you had.

Show original thread
12 replies
Odd, that looks okay.
could you post your query just in case?
Sure - Here's all the logic simplified:
import { createClient } from "next-sanity";

const sanityClient = createClient({
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || "production",
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID || "",
  apiVersion: "2021-10-21",
  useCdn: process.env.NODE_ENV === "production",
});

const res = await sanityClient.fetch(`*[_type in ["banner", "footer"]] {
  _type == "footer" => {
    ...
  }
}`);
Alternatively, do you perhaps have some query to suggest for fetching multiple documents while dereferencing their content?
e.g.

*[_type == "footer"] {
  ...,
  socials[] {
    ...,
    social->
  }
}
But applied for multiple documents in a single query
What exactly are you trying to do, if I may ask?
Just need to dereference documents within documents so their content can be accessible
yes there is a way to do it, but I cannot help unless I understand/have an example to work with 🙂This
wonderful groq tutorial (interactive) by
user B
can help you quite a bit as well as this article in our docs about groq
Thanks for the links, it looks pretty great but it doesn't really touch on what I'm looking for
Essentially, let's imagine I have a document that references another document. When querying it we don't receive the actual document, but rather the reference of it. Instead, what I would need is the actual document dereferenced.

In other words if this is the schema:

export default {
  name: "footer",
  title: "Footer",
  type: "document",
  fields: [
    {
      name: "title",
      title: "Title",
      type: "string",
    },
    {
      name: "socials",
      title: "Socials",
      type: "array",
      of: [
        {
          name: "social",
          title: "Social",
          type: "reference",
          to: { type: "social" },
        },
      ],
    },
  ],
};
To get the
footer
document with the dereferenced
social
document I'd need to use this query:
*[_type == "footer"] {
  ...,
  socials[] {
    ...,
    social->
  }
}
Now, what would I do if I need to do it for multiple documents? I can of course write multiple queries but for effectiveness I was looking for some way to fetch them all in one, e.g.:

*[_type in [ footer, otherDocument ]]
Only problem with that, is I'm not sure how I'd go about setting up the fields for each as the query above on the thread doesn't seem to work

Let me know if that clarifies, can retry in different terms if not
🙂
Since you need to explicitly dereference you fields, I think it would be better to go about it this way:
{
  "footer": *[_type =='footer'] {...//whatever fields you need to dereference},
  "otherDocument": *[_type == 'otherDocument']{...//whatever fields you need to dereference}
}
That is, unless the fields you'll be dereferencing are exactly the same in each document type.
Spot on! Wasn't aware of that syntax, that's very handy - Thank you!
Spot on! Wasn't aware of that syntax, that's very handy - Thank you!
You're welcome!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?