How to fill arrays of references in a single query - sanity

I have a schema type Page which has an array of blocks:
{
title: 'Page',
name: 'page',
type: 'document',
fields: [
...
{
title: 'Blocks',
name: 'blocks',
type: 'array',
of: [
{type: 'tileGrid'},
{type: 'otherType'}
],
options: {
editModal: 'fullscreen'
}
}
]
}
The type tileGrid has the following fields:
{
title: 'Tiles',
name: 'tiles',
type: 'array',
of: [{
type: 'reference',
to: [
{type: 'tile'}
]
}]
}
So the tile type is deeply nested page.blocks[].tiles[].tile.
How can I query page and fill in the tile references in the same query?

Since tile is a reference, you need the dereferencing operator, rather than the dot operator. This should work: page.blocks[].tiles[]->.

Related

Reference to array of objects in Sanity

Im having issues with references in Sanity. Im setting some color themes in the root of my Sanity schema:
defineField({
name: 'articletheme',
title: 'Article theme',
description: 'Create 4 themes for article blocks',
type: 'array',
validation: (Rule) => Rule.required(),
of: [{ type: 'articleThemeBlock' }],
}),
In one of the blocks I would like to reference the theme array to select which color theme that block should use.
Ive tried this, but it fails:
defineField({
name: 'theme',
title: 'Theme',
type: 'reference',
to: [
{
type: 'array',
of: [
{
type: 'articletheme',
},
],
},
],
}),
Any suggestions?
Very confusing but the your second schema above looks incorrect, try this -
defineField({
name: 'theme',
title: 'Theme',
type: 'array', // changed from reference to array
to: [
{
type: 'reference', // changed from array to reference
of: [
{
type: 'articletheme',
},
],
},
],
}),
Try it like this, type array, an array OF reference, referencing TO type articletheme
`
defineField({
name: 'theme',
title: 'Theme',
type: 'array', // changed from reference to array
of: [
{
type: 'reference', // changed from array to reference
to: [
{
type: 'articletheme',
},
],
},
],
}),
`

How do I limit the amount of document of a schema in Sanity?

For example, i have a schema called 'Blog'. i don't want there to be multiple 'Blog' entries, and only allow one entry.
export default {
name: 'blog',
type: 'document',
title: 'Blog',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'content',
title: 'Content',
type: 'array',
of: [{ type: 'block' }],
},
],
}
according to the doc
The type: 'document' property tells the studio that it should make it possible to make new animal documents.
i tried to remove type: 'document' from the schema, but got an error.

Sanity Array of Objects

I'm attempting to transform all my frontmatter from a legacy git based CMS into Sanity's ironically named CMS but I'm having difficulties with the arrays. For reference, here is my frontmatter:
resources.md
title: "Resources"
heading: "Check out our resources"
resources_list:
- title: User Manual
icon: "/assets/manual.jpg"
asset: "/assets/user-manual.pdf"
First I created a document type for the resources page and added the array to the fields:
resources.js
export default {
name: 'resourcesPage',
title: 'Resources Page',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string'
},
{
name: 'heading',
title: 'Heading',
type: 'string'
},
{
name: 'resourcesList',
title: 'Resources List',
type: 'array',
of: [
{
type: 'object',
fields: [
{
title: 'Title',
name: 'title',
type: 'string'
},
{
title: 'Icon',
name: 'icon',
type: 'image'
},
{
title: 'Asset',
name: 'asset',
type: 'file'
}
]
}
],
}
]
}
Then I get the follwoing error after I attempt to run sanity graphql deploy
Error: Encountered anonymous inline object "object" for field/type
"resourcesList". To use this field with GraphQL you will need to create
a top-level schema type for it. See
https://docs.sanity.io/help/schema-lift-anonymous-object-type
I follow their vague docs by creating another schema type for the object I want to place in my array:
resourceObj.js
export default {
type: 'object',
title: 'Resource',
name: 'resourceObj',
fields: [
{
title: 'Title',
name: 'title',
type: 'string'
},
{
title: 'Icon',
name: 'icon',
type: 'image'
},
{
title: 'Asset',
name: 'asset',
type: 'file'
}
]
}
Then I add it to the resources page schema:
export default {
name: 'resourcesPage',
title: 'Resources Page',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string'
},
{
name: 'heading',
title: 'Heading',
type: 'string'
},
{
name: 'resourcesList',
title: 'Resources List',
type: 'array',
of: [
{
type: 'resourceObj',
}
],
}
]
}
When I run sanity graphql deploy again I get the following error:
Error: resourcesPage - (document) / fields / resourcesList - (array) / of / <unnamed_type_#_index_0> - (resourcesObj)
Why would sanity not recognize my object?
In order to use objects in an array, you need to create a separate file for the object in the schema directory and make sure to import it on schema.js:
// First, we must import the schema creator
import createSchema from 'part:#sanity/base/schema-creator'
// Then import schema types from any plugins that might expose them
import schemaTypes from 'all:part:#sanity/base/schema-type'
import resourcesPage from './ownerGarage'
import resourceObj from './resourceObj'
// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
// We name our schema
name: "default",
// Then proceed to concatenate our document type
// to the ones provided by any plugins that are installed
types: schemaTypes.concat([
/* Your types here! */
resourcesPage,
resourceObj
]),
});

Filter query result by field value inside array of objects [Sanity.io & GROQ]

I'm trying to find a product variant inside my list of products(on sanity.io using GROQ), to do so, I have the sku of the variant that I want.
The query I'm using is
*[_type == "product" && variants[].sku.current =="kit-kat-wasabi-5" ]
But this query returns an empty array. I'm sure that the sku is correct because if I leave the filter aside, and fetch all I can find it.
I tried replacing the "==" with match, but the result is the same.
my schemas are
procuct
export default {
name: 'product',
title: 'Product',
type: 'document',
fields: [
{
name: 'title',
title: 'Inner Title',
type: 'string'
},
{
title: 'SKU',
name: 'sku',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
validation: Rule => Rule.required()
},
{
name: 'titleWebsite',
title: 'Title Website',
type: 'localeString'
},
{
name: 'active',
title: 'Active',
type: 'boolean'
},
{
name: 'mainImage',
title: 'Imagem',
type:"image"
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
}
},
{
title: 'Base Price',
name: 'basePrice',
type: 'localeCurrency'
},
{
title: 'Quantidade',
name: 'qty',
type: 'number'
},
/* {
title: 'Default variant',
name: 'defaultProductVariant',
type: 'productVariant'
},*/
{
title: 'Variants',
name: 'variants',
type: 'array',
of: [
{
title: 'Variant',
type: 'productVariant'
}
]
},
{
title: 'Tags',
name: 'tags',
type: 'array',
of: [
{
type: 'string'
}
],
options: {
layout: 'tags'
}
},
{
name: 'vendor',
title: 'Vendor',
type: 'reference',
to: {type: 'vendor'}
},
{
name: 'blurb',
title: 'Blurb',
type: 'localeString'
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [
{
type: 'reference',
to: {type: 'category'}
}
]
},
{
name: 'body',
title: 'Body',
type: 'localeBlockContent'
}
],
preview: {
select: {
title: 'title',
manufactor: 'manufactor.title',
media: 'mainImage'
}
}
}
And productVariant
export default {
title: 'Product variant',
name: 'productVariant',
type: 'object',
fields: [
{
title: 'Title',
name: 'title',
type: 'string'
},
{
title: 'Title Website',
name: 'titleWebsite',
type: 'localeString'
},
{
title: 'Weight in grams',
name: 'grams',
type: 'number'
},
{
title: 'Price',
name: 'price',
type: 'localeCurrency'
},
{
title: 'SKU',
name: 'sku',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
validation: Rule => Rule.required()
},
{
title: 'Taxable',
name: 'taxable',
type: 'boolean'
},
{
name: 'blurb',
title: 'Blurb',
type: 'localeString'
},
{
name: 'images',
title: 'Images',
type: 'array',
of: [
{
type: 'image',
options: {
hotspot: true
}
}
]
},
{
title: 'Quantidade',
name: 'qty',
type: 'number'
},
{
title: 'Bar code',
name: 'barcode',
type: 'barcode'
}
]
}
This is a known bug in GROQ when traversing arrays. This will introduce breaking changes if it were to be fixed in GROQ v1. It will therefore be fixed in GROQ v2.
Here is a bug report explaining the issue: https://github.com/sanity-io/sanity/issues/1557. You can show your interest in this problem here.
There's a working draft for version two here: https://github.com/sanity-io/groq.
Regarding your schema, I would consider to change the type of the sku field to be something else, for example a string, and create a new field for the slug which has its source property set to the SKU to be automatically be generated by that field. Documentation for that can be found here: https://www.sanity.io/docs/slug-type.

Why Doesn't Prepare Render Properly in Sanity.IO

I am trying to customize the prview section for a document insanity.io. To that extent, I have created the following document:
export default {
name: 'news',
type: 'document',
title: 'News',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
...
{
name: 'author',
title: 'Author',
type: 'string',
},
...
],
preview: {
select: {
title: 'title',
subtitle: 'author',
}
}
}
This works exactly as I want in Studio. The title section in the preview pane shows the title of the document and the subtitle section shows the name of the author.
However, if I try to modify the output of author by using prepare, then it no longer works. For instance, take a look at the following variation of the same document:
export default {
name: 'news',
type: 'document',
title: 'News',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
...
{
name: 'author',
title: 'Author',
type: 'string',
},
...
],
preview: {
select: {
title: 'title',
author: 'author',
}
},
prepare(selection) {
const { author } = selection
return {
...selection,
subtitle: author && `${author} is the author`
}
}
}
The title preview field is rendered, but nothing shows up in the subtitle section. However, as far as I understand -- this should work. And I wondering why not.
Any ideas?
prepare is actually a function called in preview. You have it as a seperate field of the root object. Move prepare inside preview like so:
preview: {
select: {
title: 'title',
author: 'author'
},
prepare(selection) {
const { author } = selection
return {
...selection,
subtitle: author && `${author} is the author`
}
}
}