Help with setting initial values for array of references in Sanity schema

32 replies
Last updated: Jun 8, 2022
  "authors": [
    {
      "_type": "reference",
      "_key": "e4072b1d3618",
      "_ref": "1fcfcd8f-db73-40a7-ac74-684a7a97a2e6"
    },
    {
      "_type": "reference",
      "_key": "e2d64d5f79e3",
      "_ref": "5f700b37-47cd-4a0f-b541-2176046ce962"
    }
  ],

How do I groq this?

I tried:

 *[_type == "person"]{
          "authors": {
                "_type": "reference",
                "_ref": _id
            }
          }

But it gives me:
  "authors": [
    {
      "_key": "81f684c7699b7bc2f8d0a3f5d983cd5f",
      "authors": {
        "_ref": "1fcfcd8f-db73-40a7-ac74-684a7a97a2e6",
        "_type": "reference"
      }
    },
    {
      "_key": "1769186994b00072dcb9acc9910880f2",
      "authors": {
        "_ref": "5f700b37-47cd-4a0f-b541-2176046ce962",
        "_type": "reference"
      }
    }
  ]

Tried many groq queries but just cant figure this one out, any help would be appreciated. Thanks
Jun 8, 2022, 7:19 AM
You need to resolve the references, as explained in the documentation or shown in the cheat sheet :
authors[] -> { ... }
Jun 8, 2022, 7:29 AM
The
[]
means
authors
is an array and you want to do that for every item.
->
means resolving the reference to that document.
...
means all fields.
Jun 8, 2022, 7:30 AM
So this means “resolve all authors references and retrieve all their fields.”
Jun 8, 2022, 7:30 AM
Oh I do not want to get the reference of author, I want the groq projection to look exactly like the original one. I should probably explain I am trying to set an initialvalue for the authors field and have folowed along in this sanity video: https://www.youtube.com/watch?v=iR4JVsWF6uo
Jun 8, 2022, 7:33 AM
Oh, sorry I didn’t get that. How does your person schema look like please?
Jun 8, 2022, 7:34 AM
Have you tried:
*[_type == "person"]{
  _key,
  "_type": "reference",
  "_ref": _id
}
Jun 8, 2022, 7:35 AM
import customImage from "../../lib/custom-image";

export default {
    title: "Person",
    name: "person",
    type: "document",
    fields: [
        {
            title: "Name",
            name: "name",
            type: "string",
        },
        customImage({
            title: "Photo",
            name: "photo",
            description: "The portrait for this editor.",
        }),
        {
            title: "Bio",
            name: "bio",
            type: "text",
            description: "A short biography for this editor, to appear in articles, hub pages, etc.",
        },
    ]
};

here is my person schema
Jun 8, 2022, 7:38 AM
I want the groq projection to look exactly like this: 
  "authors": [
    {
      "_type": "reference",
      "_ref": "1fcfcd8f-db73-40a7-ac74-684a7a97a2e6"
    },
    {
      "_type": "reference",
      "_ref": "5f700b37-47cd-4a0f-b541-2176046ce962"
    }
  ],
Jun 8, 2022, 7:40 AM
But this is not valid JavaScript/JSON to begin with. You need at least a wrapping object to have a named key.
Jun 8, 2022, 7:40 AM
Or you want your projection to return an array of persons.
Jun 8, 2022, 7:40 AM
here is the full raw json:
{
  "_createdAt": "2022-06-08T07:16:41Z",
  "_id": "drafts.98b3e8a1-a3ff-4b47-9a5a-a5d567521bed",
  "_rev": "irwkbf-ico-m75-hqn-nybjc022p",
  "_type": "post",
  "_updatedAt": "2022-06-08T07:16:57Z",
  "authors": [
    {
      "_key": "e4072b1d3618",
      "_ref": "1fcfcd8f-db73-40a7-ac74-684a7a97a2e6",
      "_type": "reference"
    },
    {
      "_key": "e2d64d5f79e3",
      "_ref": "5f700b37-47cd-4a0f-b541-2176046ce962",
      "_type": "reference"
    }
  ],
  "date": "2022-06-08T07:16:37.535Z",
  "photos": {
    "_type": "image",
    "customRatio": 0
  }
}
Jun 8, 2022, 7:41 AM
I‘m a little confused, sorry. Your person schema as shown above doesn’t seem to have an array of references, so I don‘t know what you‘re trying to query.
Jun 8, 2022, 7:44 AM
Where did you get that raw JSON from? What does it represent?
Jun 8, 2022, 7:45 AM
Ah here is the authors field:
{
            title: 'Authors',
            name: 'authors',
            type: 'array',
            of: [{
                type: 'reference',
                to: [{type: 'person'}],
                options: {
                    filter: ({ document }) => {
                        const addedAuthors = document.authors
                            .map(p => p._ref)
                            .filter(Boolean)
                        return {
                            filter: '!(_id in $ids)',
                            params: {
                                ids: addedAuthors                        }
                        }
                    }
                }
            }],
            validation: (Rule) => Rule.required(),
            group: 'content'
        },
Jun 8, 2022, 7:46 AM
Ah right. If you query the
authors
field without any projection or resolution, it should return the array as you expect I believe.
Jun 8, 2022, 7:47 AM
Here is the full code for this page so it makes it easier to see what im trying do
import React from 'react'
import sanityClient from 'part:@sanity/base/client'
import { Gift } from 'phosphor-react'
import customImage from '../../lib/custom-image'

import { getIcon } from './filter'

export default {
    name: "post",
    title: "Post",
    type: "document",
    groups: [
        { title: 'Content', name: 'content', default: true },
        { title: 'SEO', name: 'seo' },
        { title: 'Settings', name: 'settings' },
    ],
    initialValue: async () => ({
        date: new Date().toISOString(),
        authors: await sanityClient.fetch(`
          *[_type == "person"]{
              _key,
              "_type": "reference",
              "_ref": _id
            }
        `)
        // authors: [
        //     {
        //         "_key": "18fdc834e74a",
        //         "_ref": "1fcfcd8f-db73-40a7-ac74-684a7a97a2e6",
        //         "_type": "reference"
        //     },
        //     {
        //         "_key": "3e9896fdaed3",
        //         "_ref": "5f700b37-47cd-4a0f-b541-2176046ce962",
        //         "_type": "reference"
        //     }
        // ],
    }),
    fields: [
        {
            name: "title",
            type: "string",
            title: "Title",
            validation: (Rule) => Rule.required(),
            group: 'content'
        },
        {
            title: 'Authors',
            name: 'authors',
            type: 'array',
            of: [{
                type: 'reference',
                to: [{type: 'person'}],
                options: {
                    filter: ({ document }) => {
                        const addedAuthors = document.authors
                            .map(p => p._ref)
                            .filter(Boolean)
                        return {
                            filter: '!(_id in $ids)',
                            params: {
                                ids: addedAuthors                        }
                        }
                    }
                }
            }],
            validation: (Rule) => Rule.required(),
            group: 'content'
        },
        {
            name: "slug",
            type: "slug",
            title: "Slug",
            options: {
                source: "title",
                maxLength: 100,
            },
            validation: (Rule) => Rule.required(),
            group: 'content'
        },
        customImage({
            title: 'Photo',
            name: 'photos',
            group: 'content',
        }),
        {
            name: "date",
            title: "Date",
            type: "datetime",
            validation: (Rule) => Rule.required(),
            group: 'content'
        },
        {
            title: 'Content',
            name: 'content',
            type: 'complexPortableText',
            group: 'content'
        },
        {
            title: 'Overlay header with transparency?',
            name: 'hasTransparentHeader',
            type: 'boolean',
            description:
                'When activated the header will overlay the first content module with a transparent background and white text until scrolling is engaged.',
            group: 'settings'
        },
        {
            title: 'Filters',
            name: 'filters',
            type: 'array',
            description: 'Define what filters are associated with this product',
            of: [
                {
                    title: 'Filter',
                    name: 'filter',
                    type: 'object',
                    fields: [
                        {
                            title: 'Filter',
                            name: 'filter',
                            type: 'reference',
                            to: [{ type: 'filter' }]
                        },
                        {
                            title: 'Which option is this for?',
                            name: 'forOption',
                            type: 'string',
                            options: {
                                list: [{ title: 'All', value: '' }],
                                from: 'options',
                                fromData: { title: 'name' },
                                joinWith: 'values'
                            }
                        }
                    ],
                    preview: {
                        select: {
                            title: 'filter.title',
                            type: 'filter.type',
                            color: 'filter.color.color',
                            forOption: 'forOption'
                        },
                        prepare({ title = 'Untitled', type, color, forOption }) {
                            const displayType = type && type.trim() ? type : 'simple'
                            const option = forOption ? forOption.split(':') : null

                            return {
                                title,
                                subtitle:
                                    option && option.length > 1
                                        ? `${option[0]}: ${option[1]}`
                                        : 'All Variants',
                                media: getIcon(displayType, color?.hex.toUpperCase())
                            }
                        }
                    }
                }
            ],
            options: {
                editModal: 'popover'
            },
            validation: Rule => Rule.unique(),
            group: 'settings'
        },
        {
            title: 'SEO / Share Settings',
            name: 'seo',
            type: 'seo',
            group: 'seo'
        }
    ]
}
Jun 8, 2022, 7:49 AM
the part im working on is the initialvalue property
Jun 8, 2022, 7:50 AM
So you’re trying to have 2 specific authors as an initial value, right?
Jun 8, 2022, 7:51 AM
yup
Jun 8, 2022, 7:53 AM
I want it to eventually get all the new authors I also add
Jun 8, 2022, 7:54 AM
Right.
Jun 8, 2022, 8:02 AM
So I’m not sure how to populate initial references. I’m searching.
Jun 8, 2022, 8:03 AM
The image is populated as a reference indeed.
Jun 8, 2022, 8:06 AM
So what I would do is query your 2 authors or whatever initial documents. And then in JS, pass that structure.
Jun 8, 2022, 8:07 AM
initialValue: () => myDocuments.map(document => ({
  _type: 'reference',
  _ref: document._id
}))
Jun 8, 2022, 8:07 AM
I’m cutting some corners here, sorry.
Jun 8, 2022, 8:09 AM
But basically, I wouldn‘t mess with groq that much.
Jun 8, 2022, 8:09 AM
Interesting, i initially thought it would be some easy groq manipulation that i might be missing. i though i could make the authors properties and objects go into an array to make it look like this:   "authors": [
    {
      "_type": "reference",
      "_key": "e4072b1d3618",
      "_ref": "1fcfcd8f-db73-40a7-ac74-684a7a97a2e6"
    },
    {
      "_type": "reference",
      "_key": "e2d64d5f79e3",
      "_ref": "5f700b37-47cd-4a0f-b541-2176046ce962"
    }
  ]

but looks like its tougher than I thought. Truly appreciate you trying though, thank you
Jun 8, 2022, 8:19 AM
For now I will just set it manually like above instead of trying to fetch the authors through groq.
Jun 8, 2022, 8:22 AM
I think we misunderstood each other. I would still recommend fetching the documents with your client. I just wouldn‘t overthink the structure in the groq query and do it in JS instead.
Jun 8, 2022, 8:25 AM
Will give it a try but am a little confused how i should go about it, is there any examples of something similar?
Jun 8, 2022, 8:34 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?