Как увеличить свойство на документ в 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 который уже используется для другого документа, запрос не будет выполнен. Мы используем это как механизм защиты от расы.

Для использования в вопросе нам нужно сделать три вещи:

  1. Получить deliveryNumber последнего созданного заказа (см. этот ответ)
  2. Инкремент на один, чтобы получить следующий deliveryNumber
  3. Создать новый заказ с тем же значением для _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)

Теперь возможно иметь initialValues в схеме, что позволяет установить автоматическое увеличение значения в схеме.

Есть сообщение об этой функции и о том, как она работает.

Автоинкремент значения

Давайте возьмем пример вопроса, вы хотите иметь номер доставки, который является возрастающим числом.

Так что считайте каждый 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 но я не уверен, возможно ли это.

Другие вопросы по тегам