Using initialValueTemplates to reference parent document fields

2 replies
Last updated: Nov 1, 2024
Hi, I want to use initialValueTemplates and create a document using the values in the parent document. According to the doc https://www.sanity.io/docs/initial-value-templates#febce15880e2 I can pass the id of the parent document, but it is just a string. Is there any way I can get the values of the specifications field (it's a ref array) to insert it in the current document?
AI Update

Good news! Yes, you can absolutely fetch the parent document's values within your initial value template. Your solution using context.getClient() is exactly the right approach.

Based on the official Initial Value Templates documentation, when you define a template in schema.templates, the value function receives two parameters:

  1. params - containing any parameters you pass (like your parentId)
  2. context - which includes helpful utilities like getClient, currentUser, schema, dataset, and projectId

Here's how to fetch parent document fields and use them in your new document:

// sanity.config.ts
import {defineConfig} from 'sanity'

export default defineConfig({
  // ...rest of config
  schema: {
    templates: (prev, context) => [
      ...prev,
      {
        id: 'child-with-parent-specs',
        title: 'Child Document',
        schemaType: 'childDocument',
        parameters: [{name: 'parentId', type: 'string'}],
        value: async (params, context) => {
          // Get a Sanity client from the context
          const client = context.getClient({apiVersion: '2024-11-01'})
          
          // Fetch the parent document with its specifications field
          const parentDoc = await client.fetch(
            `*[_id == $parentId][0]{
              _id,
              specifications
            }`,
            {parentId: params.parentId}
          )
          
          // Return initial values for the new document
          return {
            parent: {
              _type: 'reference',
              _ref: params.parentId
            },
            specifications: parentDoc?.specifications || []
          }
        }
      }
    ]
  }
})

The key points:

  1. Make the value function async so you can await the fetch operation
  2. Use context.getClient() to get a configured Sanity client - this is available in the context parameter
  3. Query with GROQ to fetch exactly the fields you need from the parent document
  4. Handle reference arrays - if specifications is a ref array, the references will be copied as-is with their _ref values intact

Your solution from the Sanity Answers thread demonstrates this perfectly! If you need to transform the references (like mapping them to a different structure), you can use .map() as you showed:

characteristics: category.characteristics.map((c: any) => ({
  _type: 'partCharacteristic', 
  characteristic: {_type: 'reference', _ref: c._ref}
}))

This pattern works great when combined with Structure Builder for creating contextual document creation flows where child documents inherit properties from their parent. Just use .initialValueTemplates() in your structure definition to specify which template should be used in that context, passing the necessary parameters like parentId.

i think i can use context.getClient and get field using groq, but is it the right way?
if interesting, i solve this like that
templates: (prev, context) => [
      ...prev,
      {
        id: 'product-by-category',
        title: 'Product by Category',
        schemaType: 'product',
        parameters: [{name: 'category', type: 'string'}],
        value: async(params: any) => {
          const category = await context.getClient({apiVersion: '2024-11-01'}).fetch(`*[_type == "category" && _id == $category][0]{_id, characteristics}`, {category: params.category})
          const characteristics = category.characteristics;
          return{
          category: {_type: 'reference', _ref: category._id},
          characteristics: characteristics.map((c: any) => ({_type: 'partCharacteristic', characteristic: {_type: 'reference', _ref: c._ref}})),
        }},
      },
    ],
  },

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?