How to merge multiple documents into a flat object in Groq

10 replies
Last updated: Oct 24, 2021
I just need a little groq help. I've got three documents I'm querying from:
*[_type == "businessName" ||
   _type == "contact" ||
   _type == "address"]
which returns the following:

[
  {
    "_createdAt": "2021-10-21T00:22:05Z",
    "_id": "address",
    "_rev": "TrMJZl8kHDIulSDqHsmmGk",
    "_type": "address",
    "_updatedAt": "2021-10-21T03:25:59Z",
    "addressLine1": "123 Main Street",
    "city": "Sometown",
    "postal": "T8A 1A1",
    "province": "AB"
  },
  {
    "_createdAt": "2021-10-21T02:39:46Z",
    "_id": "businessName",
    "_rev": "TrMJZl8kHDIulSDqHvQf8Y",
    "_type": "businessName",
    "_updatedAt": "2021-10-21T12:30:55Z",
    "businessName": "Example Business Name"
  },
  {
    "_createdAt": "2021-10-21T00:21:00Z",
    "_id": "contact",
    "_rev": "qIVfBk0FCSxuep3bFCat6O",
    "_type": "contact",
    "_updatedAt": "2021-10-21T12:20:21Z",
    "email": "<mailto:email@domain.com|email@domain.com>",
    "fax": "<tel:780-555-4444|780-555-4444>",
    "phone": "<tel:780-555-5555|780-555-5555>"
  }
]
I'd like to be able to pull the relevant info from each returned object and put it into a flat object:

{
  "businessName": "Example Business Name",
  "email": "<mailto:email@domain.com|email@domain.com>",
  "fax": "<tel:780-555-4444|780-555-4444>",
  "phone": "<tel:780-555-5555|780-555-5555>"
  "addressLine1": "123 Main Street",
  "city": "Sometown",
  "postal": "T8A 1A1",
  "province": "AB"
}
but i'm not sure how to achieve this. Any assistance would be much appreciated!
Oct 21, 2021, 12:39 PM
hi User, you can query for unique fields like this:

*[_type in ["typeA", "typeB", "typeC"]] {
  aCommonField,
  anotherCommonField,
  _type == "typeA" => {
    typeAField,
  },
  _type == "typeB" => {
    typeBField,
  },
  /* etc */
}

Oct 21, 2021, 3:03 PM
ah scratch that — I misunderstood your issue 😅
Oct 21, 2021, 3:06 PM
These all look like singleton docs, so perhaps something like this would work?

{
  "businessName": *[_type == 'businessName'][0].businessName,
  "email": *[_type == 'contact'][0].email,
  /* etc */
}
This is super tedious though,… I wonder if you’d better off stitching these docs together via JS or something else:


{
  "businessName": *[_type == 'businessName'][0].businessName,
  "contact": *[_type == 'contact'] { email, fax, phone },
  /* etc */
}
Oct 21, 2021, 3:12 PM
Thanks for the input User. I initially was going to just put the 3 queries in a
Promise.all
and spread the results into one object but I thought maybe I could do it with one query. Simpler is probably better in this case!
Oct 21, 2021, 7:11 PM
yeah I think there’s no way to ‘unwrap’ an object to parents, so for now you’d have to manually join them together… but just to be clear, you still can query for all data within one fetch without touching Promise.all, e.g.
client.fetch(`{
  "businessName": *[_type == '...'],
  "contact": *[_type == '...'],
}`)
Might help save a few extra queries!
Oct 22, 2021, 3:13 AM
Hey
user H
, actually what you want is doable:

{
  ...*[_type == 'businessName'][0],
  ...*[_type == 'contact'][0],
  /* etc */
}
It’ll merge all those docs into one single object. Note that if 2 documents have the same value name, it’ll be overwritten. GROQ is wild!
Oct 24, 2021, 3:29 PM
Hey User! Ok very cool. I’ll try out your suggestions! So a query doesn’t absolutely need the
*[]
select/filter at the start? You can just create a projection and put the filters in there?
Oct 24, 2021, 4:07 PM
Yes that’s right, a query doesn’t need to start with
*[]
, you can use a projection
Oct 24, 2021, 4:09 PM
Yes that’s right, a query doesn’t need to start with
*[]
, you can use a projection
Oct 24, 2021, 4:09 PM
Well that’s a light bulb moment. I didn’t realize that. Thank you very much for the insight User! This is incredibly helpful!
Oct 24, 2021, 4:29 PM

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?