<question>Destructuring array of references inside fieldset/nested object in GROQ</question>

4 replies
Last updated: Mar 3, 2021
Is there a way to return destructured data for an array of references when inside of a fieldset?
I'm using the tabs plugin on Sanity, and I have an array of references inside one of the tabs. However, I'm having a hard time getting past the first content object to destructure the array.

Here is the data structure:

{
  "_createdAt": "2021-01-23T18:23:03Z",
  "_id": "eb2ea4ad-b9dd-48d2-a12f-d624072c3f85",
  "_rev": "kb0HY6NIXzvB0Lryh3yfgp",
  "_type": "stylist",
  "_updatedAt": "2021-01-27T02:19:29Z",
  "content": {
    "_type": "object",
    "businessName": "...",
    "emailAddress": "...",
    "hours": [
      {
        "_key": "6ec087d3b1b8",
        "day": "Mon",
        "hoursValue": "10:00am - 8:00pm"
      },
      {
        "_key": "cebf173f6c30",
        "day": "Wed",
        "hoursValue": "10:00am - 8:00pm"
      },
      {
        "_key": "e28b97392ccc",
        "day": "Fri",
        "hoursValue": "10:00am - 6:00pm"
      },
      {
        "_key": "4e22af69c6b8",
        "day": "Sat",
        "hoursValue": "By appointment only"
      }
    ],
    "phoneNumber": "3035505676",
    "services": [
      {
        "_key": "930fef6cff22",
        "_ref": "b761952b-5280-4abc-b1cf-8f126b0b2717",
        "_type": "reference"
      },
      {
        "_key": "0474ffdda5dc",
        "_ref": "48dc64ec-04e1-45e0-a035-356a96c5d519",
        "_type": "reference"
      },
      {
        "_key": "dd7f83a6a1fc",
        "_ref": "8000399d-8782-4801-ba0b-13fbd3eabeaf",
        "_type": "reference"
      },
      {
        "_key": "e6943b847829",
        "_ref": "ac00790b-694f-4903-9c89-44a78d001d2d",
        "_type": "reference"
      }
    ],
    "suiteNumber": 202
  },
  "location": {
    "_ref": "eee608e6-47ce-4397-ad26-06fab5a329de",
    "_type": "reference"
  },
  "name": "...",
  "slug": {
    "_type": "slug",
    "current": "...-..."
  }
}
You can see the "Services" array is inside of the "Content" object, but I am unable to run something like the code block to be able to destructure the Services array like I need to in order to return the name of the service.


*[_type == "stylist" && name == "Alex Clark"] {
  name,
  content->services[]->
}
AI Update

Based on your data structure, the issue is that content is not a reference (it doesn't have _ref), it's a nested object. You can't use the dereference operator -> on regular objects, only on references.

Here's how to properly query your data:

*[_type == "stylist" && name == "Alex Clark"] {
  name,
  "services": content.services[]-> {
    name,
    // any other fields from the service document
  }
}

The key difference is:

  • Use dot notation (content.services) to access fields inside nested objects
  • Use the dereference operator (->) only on the actual references inside the array
  • Use quotes to create a custom field name in your projection

If you want to keep the entire content structure but expand the services, you can use the spread operator:

*[_type == "stylist" && name == "Alex Clark"] {
  name,
  content {
    businessName,
    emailAddress,
    phoneNumber,
    suiteNumber,
    hours,
    "services": services[]-> {
      name,
      // other service fields
    }
  }
}

Or if you want to expand services while keeping all other content fields as-is:

*[_type == "stylist" && name == "Alex Clark"] {
  name,
  content {
    ...,
    "services": services[]-> {
      name
    }
  }
}

The ... (spread operator) includes all fields from the content object, and then you override just the services array with the dereferenced version.

The fundamental rule here from the GROQ projections documentation: -> only works on references (objects with _ref), while dot notation traverses into regular nested objects. Your content object is just a regular nested object (even though it has _type: "object"), so you need to use content.services to access the array before dereferencing each item.

Show original thread
4 replies
Hi Austin. What about:

*[_type == "stylist" && name == "Alex Clark"] {
  name,
  "services": content.services[]->
}
or


*[_type == "stylist" && name == "Alex Clark"] {
  name,
  content {
    services[]->
  }
}

Hi Geoff! These could be the golden ticket! Let me try them out πŸ™‚
You're the best! Worked like a charm πŸ‘. I opted for this structure:

*[_type == "stylist" && slug.current == $slug] {
    name,
    slug,
    content {
      bio,
      website,
      phoneNumber,
      emailAddress,
      hours,
      facebookUsername,
      instagramUsername,
      services[]->
    },
    location->,
}[0]`
Glad to hear it, Austin! πŸ™‚

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?