Sanity.io GROQ query for array of objects

6.5k Views Asked by At

I'm learning to code and now I am on the stage of a small pet project with Sanity as a CMS. Long story short, making an API I'm trying to fetch cocktails data with votes for the cocktails. The votes are stored within persons who voted:

GROQ query

*[
  _type == "cocktail" &&
    !(_id in path('drafts.**'))
 ] {
  name,
  _id,
    "votes" : *[_type == "person" && references(^._id)] {
    votes[] {
        score,
        "id": cocktail._ref
        }
    } 
}

which returns

[
  {
    "_id": "pdUGiuRzgLGpnc4cfx76nA",
    "name": "Cuba Libre",
    "votes": [
      {
        "votes": {
          "id": "pdUGiuRzgLGpnc4cfx76nA",
          "score": 2
        }
      },
      {
        "votes": {
          "id": "pdUGiuRzgLGpnc4cfx76nA",
          "score": 2
        }
      }
    ]
  },
  {
    "_id": "pdUGiuRzgLGpnc4cfxBOyM",
    "name": "The ERSH7",
    "votes": []
  }
]

As you can see, the merge provides embedded arrays of votes meanwhile I want sth like:

[{
  ...cocktail attributes...
  "votes" : [
    {score: 2, id: pdUGiuRzgLGpnc4cfx76nA},
    {score: 2, id: pdUGiuRzgLGpnc4cfx76nA}
  ]
 }
... more cocktails....
]

Trying to get this I modified the query:

*[
  _type == "cocktail" &&
    !(_id in path('drafts.**'))
 ] {
  name,
  _id,
    "votes" : *[_type == "person" && references(^._id)].votes[] {
        score,
        "id": cocktail._ref
    }
}

which should take a projection from every element of the votes arr. Unfortunately I get empty arrays:

[
{
  "_id": "pdUGiuRzgLGpnc4cfx76nA",
  "name": "Cuba Libre",
  "votes": [
    {},
    {}
  ]
}
...more cocktails
]

How can I achieve the desired result? Thank you for reading! Would appreciate any help!

2

There are 2 best solutions below

0
On

Yes, had similar struggles with "flattening" the projections my self. I solved it with dot-syntax. Try just adding .votes on your first attempt:

*[
  _type == "cocktail" &&
  !(_id in path('drafts.**'))
]
{
  name,
  _id,
  "votes" : *[_type == "person" && references(^._id)] {
    votes[] {
      score,
      "id": cocktail._ref
    }
  }
  .votes
}

If this is correct, the whole query can be simplified but I'm not at the level, yet, where I can do that without testing against a similar set ,'-)

0
On

Actually, GROQ has syntax to flatten array starting from v2021-03-25

find this example:

{
  'nestedArray': [
    {'foo': [1,2,3,4,5]},
    {'foo': [6,7,8,9,10,11,12]},
    {'foo': [13,14,15]},
  ]
}{
  'stillNestedArray': @.nestedArray[].foo,
  'flatArray': @.nestedArray[].foo[]
}

Note the [] right after foo - this is what's flatten it

So the original query from the question should look like

*[
  _type == "cocktail" &&
    !(_id in path('drafts.**'))
 ] {
  name,
  _id,
    "votes" : *[_type == "person" && references(^._id)] {
    votes[] {
        score,
        "id": cocktail._ref
        }
    }.votes[] 
}