Studio

Cross Dataset Reference

A schema type for referencing documents in another dataset within the same project.

Cross-dataset references connect documents across datasets. They are closely related to the reference type, but they have their own distinct schema type, crossDatasetReference, and the two cannot be used interchangeably.

To set up your datasets for cross-dataset referencing, see Cross-dataset references.

This is a paid feature

This feature is available on certain Enterprise plans. Talk to sales to learn more.

Gotcha

Properties

  • Requiredtype

    Value must be set to crossDatasetReference.

  • Requiredname

    The field name. This will be the key in the data record.

  • Requiredto

    An array of objects naming the types from the referenced dataset that should be available in the referencing studio. type is required. icon and title are optional. For example: [{type: 'someTypeFromAnotherDataset', preview: {select: {title: 'title'}}}].

    Each entry also needs a preview in practice. The referencing dataset has no access to the referenced dataset’s schema, so search and preview cannot be inferred and the Studio requires it at runtime. Note that the published CrossDatasetReferenceDefinition types it as optional, so TypeScript will not catch a missing preview.

    You may name several types in the to array, but each field is limited to types from a single dataset.

  • Requireddataset

    The name of the referenced dataset.

  • A function that is invoked with the type and id of the referenced document, and returns a URL string pointing directly at that document in its own studio. Used to build the intent link shown on the reference preview.

    Example:

    studioUrl: ({type, id}) => `https://<your-studio-host>/structure/intent/edit/id=${id};type=${type}/`

  • Default false. If set to true the reference will be made weak. This allows references to point at documents that may or may not exist, such as a document that has not yet been published or a document that has been deleted (or indeed an entirely imagined document).

  • Human readable label for the field.

  • If set to true, this field will be hidden in the studio. You can also return a callback function to use it as a conditional field.

  • If set to true, this field will not be editable in the content studio. You can also return a callback function to use it as a conditional field.

  • Short description to editors how the field is to be used.

  • The initial value used when creating new values of this type. Can be a literal value, or a resolver function that returns a literal value or a promise that resolves to one.

  • Marks a field or document type as deprecated in the studio interface and displays a user-defined message defined by the single required reason property.

    If you deploy a GraphQL API schema, this property will translated into the @deprecated directive.

Options

  • Additional GROQ-filter to use when searching for target documents. The filter will be added to the already existing type name clause.

    If a function is provided, it is called with an object containing document, parent and parentPath properties, and returns an object containing filter and params. The function may be async and return a promise resolving to that object.

    Note: The filter only constrains the list of documents returned at the time you search. It does not guarantee that the referenced document will always match the filter provided.

  • Object of parameters for the GROQ filter specified in filter.

    Only valid with the string form of filter. When filter is a function it is typed as never, because the function returns its own params.

Validation

  • Ensures that this field exists.

  • Creates a custom validation rule.

  • Sets a custom error message for the preceding validation rule.

  • Sets a custom warning message for the preceding validation rule. Warnings do not prevent publishing.

  • Info messages are purely informational and do not prevent publishing.

  • Gets the value of a sibling field to use in validation. Useful for rules that depend on another field.

  • Discards the validation rules set before it in the chain and makes the field optional. Rules chained after it still apply.

Minimal example

A minimal example of a crossDatasetReference field:

Input

import {defineType} from 'sanity'

export const personReferenceType = defineType({
  title: 'Person in another dataset',
  name: 'personReference',
  type: 'crossDatasetReference',
  dataset: 'production',
  to: [
    {
      type: 'person',
      preview: {
        select: {
          title: 'name',
          media: 'image',
        },
      },
    },
  ],
})

Response

{
  "_type": "personReference",
  "_ref": "person_andrew-stanton",
  "_dataset": "production",
  "_projectId": "k1a2b3c4"
}

The stored _type is the name of your field’s schema type, not the literal string crossDatasetReference. The Studio also writes _projectId on every value: it is the id of the project both datasets belong to, and preview resolution needs it.

Weak reference

Setting weak: true lets you publish a document whose cross-dataset reference points at a document that does not exist. The Studio still flags the missing target; it no longer blocks publishing.

Input

import {defineType} from 'sanity'

export const personReferenceType = defineType({
  title: 'Person in another dataset',
  name: 'personReference',
  type: 'crossDatasetReference',
  dataset: 'production',
  weak: true,
  to: [
    {
      type: 'person',
      preview: {
        select: {
          title: 'name',
          media: 'image',
        },
      },
    },
  ],
})

Response

{
  "_type": "personReference",
  "_ref": "person_andrew-stanton",
  "_dataset": "production",
  "_projectId": "k1a2b3c4",
  "_weak": true
}

Reference multiple types

The directors field is an array that can contain both person and bovinae (in the rare occasion a cow would direct a movie) references:

Input

import {defineType} from 'sanity'

export const personOrCowReferenceType = defineType({
  title: 'Person or cow in another dataset',
  name: 'personOrCowReference',
  type: 'crossDatasetReference',
  dataset: 'production',
  to: [
    {
      type: 'person',
      preview: {
        select: {
          title: 'name',
          media: 'image',
        },
      },
    },
    {
      type: 'bovinae',
      preview: {
        select: {
          title: 'name',
          media: 'avatar',
        },
      },
    },
  ],
})

Response

[
  {
    "_type": "personOrCowReference",
    "_ref": "person_andrew-stanton",
    "_dataset": "production",
    "_projectId": "k1a2b3c4"
  },
  {
    "_type": "personOrCowReference",
    "_ref": "bovinae_ferdinand-bull",
    "_dataset": "production",
    "_projectId": "k1a2b3c4"
  }
]

Additional static filter

If providing a target schema type is not enough to provide a meaningful set of search results, you may want to further constrain the search query:

Input

import {defineType} from 'sanity'

export const personReferenceType = defineType({
  title: 'Person in another dataset',
  name: 'personReference',
  type: 'crossDatasetReference',
  dataset: 'production',
  to: [
    {
      type: 'person',
      preview: {
        select: {
          title: 'name',
          media: 'image',
        },
      },
    },
  ],
  options: {
    filter: 'role == $role',
    filterParams: {role: 'director'},
  },
})

Response

{
  "_type": "personReference",
  "_ref": "person_steven-spielberg",
  "_dataset": "production",
  "_projectId": "k1a2b3c4"
}

Additional dynamic filter

If you want to further constrain the search result, but need properties from the surrounding document or object/array, you can use the function form for filter:

Input

import {defineType} from 'sanity'

export const personReferenceType = defineType({
  title: 'Person in another dataset',
  name: 'personReference',
  type: 'crossDatasetReference',
  dataset: 'production',
  to: [
    {
      type: 'person',
      preview: {
        select: {
          title: 'name',
          media: 'image',
        },
      },
    },
  ],
  options: {
    filter: ({document}) => {
      // Always check for document properties before using them
      if (!document.releaseYear) {
        return {
          filter: 'role == $role',
          params: {role: 'director'},
        }
      }

      return {
        filter: 'role == $role && birthYear >= $minYear',
        params: {
          role: 'director',
          minYear: document.releaseYear,
        },
      }
    },
  },
})

Response

{
  "_type": "personReference",
  "_ref": "person_steven-spielberg",
  "_dataset": "production",
  "_projectId": "k1a2b3c4"
}

Nonexistent reference

Sometimes the reference field may show an error message like <nonexistent reference>. This usually happens when creating documents with a client library and can mean one of two things:

  • The document with the ID you are referencing does not exist
  • The field does not allow references to the document type of the document ID you tried to reference

To resolve it:

  • Check that the referenced document exists and has been published; cross-dataset references cannot resolve drafts.
  • Check that the document’s _type is named in the field’s to array.
  • If you are creating the reference before its target exists, the mutation is rejected by cross-dataset reference validation. The client accepts a skipCrossDatasetReferenceValidation mutation option (default false) that skips that check for the mutation. It skips validation only: it does not bypass the plan gate or any API version gate, and it does not make the reference resolve.

Was this page helpful?