Как увеличить свойство на документ в Sanity?
Мы создаем систему, где пользователи могут отправлять заказы. Заказы имеют возрастающее свойство deliveryNumber
; новый заказ должен получить DeliveryNumber, который на один выше, чем предыдущий заказ.
Есть ли встроенная поддержка для этого в Sanity?
Если нет, как мы можем достичь этого, не рискуя столкновениями из-за условий гонки?
5 ответов
Я только что заново открыл этот вопрос и подумал, что должен обновить его, поскольку (в течение некоторого времени) был способ сделать именно то, что вы спрашиваете:
Вот пример использования клиента Sanity Javascript:
const sanityClient = require('@sanity/client')
const client = sanityClient({
projectId: 'my-project-id',
dataset: 'my-dataset',
token: 'sanity-auth-token',
useCdn: false
})
client
.patch('order-123') // Document ID to patch
.inc({deliveryNumber: 1}) // Increment field by 1
.commit() // Perform patch and return a promise
.then(updatedOrder => {
console.log('Order delivery number', updatedOrder.deliveryNumber)
})
.catch(err => {
console.error('Ouch. Update failed: ', err.message)
})
Если вы не обращаетесь к Sanity через Javascript, вы можете сделать то же самое, используя HTTP API.
Насколько я знаю, пока нет встроенной поддержки увеличения свойств для каждого нового документа. Однако вы можете достичь этого самостоятельно для документов с одним увеличивающимся свойством (или если все увеличивающиеся свойства могут быть выведены из одного увеличивающегося свойства).
метод
Для этого мы используем тот факт, что при создании нового документа вы можете установить _id
вместо того, чтобы позволить Sanity создать его для вас. Если вы попытаетесь создать документ с _id
который уже используется для другого документа, запрос не будет выполнен. Мы используем это как механизм защиты от расы.
Для использования в вопросе нам нужно сделать три вещи:
- Получить
deliveryNumber
последнего созданного заказа (см. этот ответ) - Инкремент на один, чтобы получить следующий
deliveryNumber
- Создать новый заказ с тем же значением для
_id
а такжеdeliveryNumber
Если два заказа размещены одновременно, то есть попытка создать два заказа с одинаковым deliveryNumber
последний запрос, который обрабатывается Sanity, не будет выполнен, потому что _id
как первый. До тех пор, пока он не провалится, каждый заказ должен иметь уникальный deliveryNumber
один выше, чем предыдущий.
Когда это не удается
Если заказы создаются в результате взаимодействия с пользователем, я предлагаю уведомить пользователя о сбое и попросить его повторить попытку. Это случается не часто и почти наверняка не дважды подряд.
Однако, если вы должны программно обеспечить повторную попытку до тех пор, пока не добьетесь успеха, я предлагаю отступить на случайный промежуток времени (экспоненциально увеличивающийся при каждой неудаче), прежде чем пытаться снова.
осуществимость
Чем чаще создаются заказы, тем менее жизнеспособным является это решение. Я полагаю, что для большинства систем это вряд ли даст сбой.
Я хотел создать поле генерации автоматического случайного идентификатора для каждого нового документа. Я пробовал все вышеупомянутые методы, но они не работают для меня. Моя вменяемая версия говорит, что выборка устарела, не используйте. И он всегда возвращает объект со значением 1
Тогда я обнаружил, что этот трюк работает для меня.
{
name: "docid",
title: "ID",
type: "number",
initialValue: () => {
let d = new Date();
return d.getTime();
},
}
Он всегда будет возвращать случайное и уникальное число. Это простая маленькая хитрость для тех, кто хотел такое поле.
Прочитав все ответы выше, я пришел к своему простому решению по автоматизации присвоения номеров документов.
Сначала я создаю такое поле для номера документа
// ...
{
name: 'docnum',
title: 'Document Number',
type: 'number',
},
// ...
затем я создаю помощник initialValue внизу
import sanityClient from 'part:@sanity/base/client';
// ...
initialValue: async () => {
const query = '*[_type == "documentName"] | order(_createdAt desc){docnum}';
const result = await sanityClient.fetch(query);
if (result.length > 0) {
return { docnum: hasil[0].docnum + 1 };
} else {
return { docnum: 1 };
}
},
// ...
при таком подходе мой первый документ будет иметь начальное значение docnum
1. И более поздний документ будет иметь начальное значение last + 1. Я использую последнюю версию, кстати, (1.150.2)
Теперь возможно иметь initialValue
s в схеме, что позволяет установить автоматическое увеличение значения в схеме.
Есть сообщение об этой функции и о том, как она работает.
Автоинкремент значения
Давайте возьмем пример вопроса, вы хотите иметь номер доставки, который является возрастающим числом.
Так что считайте каждый order
документ и увеличьте его на единицу, чтобы использовать его как initialValue
для нового документа.
Схема order.js
import client from 'part:@sanity/base/client';
export default {
title: "Order",
name: "order",
type: "document",
initialValue: async () => ({
deliveryNumber: (await client.fetch(`//groq
count(*[_type == "order"])
}) + 1
}),
fields: [
{
title: "Delivery number",
name: "deliveryNumber",
type: "number"
},
// other fields
]
}
Не уверен, что есть более простой способ, но он работает. Было бы здорово, если бы у нас был помощник - что-то вродеautoIncrement()
Возможная реализация:
const autoIncrement = async type = (await client.fetch(`//groq
count(*[_type == "${type}"])
}) + 1
// usage:
{
// ...,
initialValue: async () => ({
deliveryNumber: await autoIncrement("order")
}),
// ....
}
Примечание. Было бы неплохо, если бы это работало без async/await и без передачи типа вautoIncrement
но я не уверен, возможно ли это.