GROQ defined() filter not working despite non-empty field

6 replies
Last updated: Mar 8, 2022
defined(Field) => Field. inside my query after console logging totally disappeared. Even if I do have one field which is not empty. Any idea?
AI Update

I can see what's happening here! The defined(field) => field syntax is GROQ's conditional projection pair syntax, and it's likely disappearing because of how the => operator works with boolean conditions.

The => operator in GROQ projections is a conditional pair that only includes the field when the left side evaluates to true. The issue is that defined(field) returns a boolean, not the actual field value, so when you write defined(field) => field, you're saying "if defined(field) is true, include field", but the syntax might not be working as expected in your context.

Here's what's probably happening and how to fix it:

The Problem:

{
  defined(myField) => myField  // This might not work as expected
}

Better Solutions:

  1. Simple conditional with default value using select():
{
  "myField": select(
    defined(myField) => myField,
    "default value"
  )
}
  1. Direct field reference (fields are automatically omitted if undefined):
{
  myField  // Will be included if it exists
}
  1. Using coalesce for fallback:
{
  "myField": coalesce(myField, "fallback")
}
  1. Conditional projection with proper syntax:
{
  defined(myField) => {
    "myField": myField
  }
}

The key issue is that the => operator in projections works as a conditional pair where the left side is evaluated as a boolean condition. When you use defined(field) => field, GROQ evaluates defined(field) (which returns true/false), and if true, it should include field. However, this syntax can be tricky and doesn't always behave as expected, especially if the field reference on the right side isn't in the correct scope.

Looking at the GROQ query cheat sheet, you can see examples of conditional projections like:

*[_type=='movie']{
  ...,
  releaseDate >= '2018-06-01' => {
    "screenings": *[_type == 'screening' && movie._ref == ^._id]
  }
}

The select() function from the GROQ conditionals documentation is usually more reliable for conditional field inclusion.

Debug tip: Console log the entire query result first without the projection to verify your field actually exists in the source documents, then gradually add your projection logic. The select() function is usually the most reliable approach for conditional field inclusion.

Show original thread
6 replies
user A

Video enabled, poster, platform and url by default return null. I have one article which has these values. But I have tried like checking to see if one of those fields is defined else don’t show it in the console log. But defined just removes the all the video fields even with one post which has a video.


"featured": *[_id == "featuredSettings"][0] {
    featuredArticles[] -> {
      title,
      body,
      publishedAt,
      author -> {
        name,
        featuredImage,
      },
      videoEnabled,
      videoPoster,
      videoPlatform,
      videoURL,
      'slug': slug.current,
    }
  },

How are you trying to use
defined()
? Does it look like this?

"featured": *[_id == "featuredSettings"][0] {
  featuredArticles[]-> {
    title,
    body,
    publishedAt,
    author-> {
      name,
      featuredImage,
    },
    defined(videoEnabled) => videoEnabled,
    defined(videoPoster) => videoPoster,
    defined(videoPlatform) => videoPlatform,
    defined(videoURL) => videoURL,
    'slug': slug.current,
  }
},
Exactly when I console log this QUERY the fields are not there. While 1 post does have all the fields and is published
I believe the API requires the return to be wrapped in curly braces. Could you try this?

"featured": *[_id == "featuredSettings"][0] {
  featuredArticles[]-> {
    title,
    body,
    publishedAt,
    author-> {
      name,
      featuredImage,
    },
    defined(videoEnabled) => {videoEnabled},
    defined(videoPoster) => {videoPoster},
    defined(videoPlatform) => {videoPlatform},
    defined(videoURL) => {videoURL},
    'slug': slug.current,
  }
},

user A
Thanks for the late reply. This does the trick. Could you explain me why it works with curly brackets only?
Hi Nino. This conditional form is syntactic sugar for a spread select function, as we see toward the bottom of the code block here . The first example in that block can use strings on the right side of the pair because there is a key to which it’s assigned:
popularity
. With the shorthand conditional, those curly braces are mandatory as we’re not returning a string value to a key, but one or more attributes back to the projection. Hope that makes sense, and glad it’s working for you.

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?