В главе Руководство по сборке с помощью Serverless AWS, посвященной DynamoDB, я упоминаю об использовании Document Client для связи с DynamoDB вместо некоторых других альтернатив, таких как клиент более низкого уровня. В этом посте я хотел бы обсудить и привести примеры кода для некоторых конкретных API DynamoDB. Когда я начал использовать Document Client, у меня были небольшие проблемы с переводом вызовов клиента нижнего уровня и API в вызовы Document Client, но, увидев несколько примеров и прочитав, как я преобразовываю полезные нагрузки, я надеюсь, что все это будет намного проще для меня. ты. В качестве примечания: то, что я покажу в этом посте, использует AWS Javascript SDK v3. Хотя более ранние версии (и, возможно, будущие версии), скорее всего, будут выглядеть одинаково, этот код предназначен специально для версии 3.

Преобразование полезной нагрузки для включения типов данных для вызовов DynamoDB может быть утомительным. Для собственного понимания я использовал клиент SDK более низкого уровня для ручного кодирования типов DynamoDB, и после этого я предпочел Document Client из-за простоты использования. Document Client использует собственные типы Javascript для заключения типа данных для DynamoDB, а затем преобразует полезные данные для нас.

Document Client в SDK — это тонкий слой поверх низкоуровневого/обычного клиента, который выполняет преобразование. Он доступен в пакете @aws-sdk/lib-dynamodb, но @aws-sdk/client-dynamodb по-прежнему требуется.

Прежде чем я начну показывать примеры кода, я хочу отметить пару предположений, которые будет делать код.

Во-первых, создается таблица DynamoDB, и имя таблицы доступно через переменную среды с именем TABLE_NAME. В примерах кода вы увидите TableName: process.env.TABLE_NAME.

Код также предполагает, что таблица настроена на использование ключа секции с именем id и ключа сортировки с именем secondaryId. Это будет видно на примерах, похожих на следующие.

И имена разделов, и ключи сортировки могут быть настроены по вашему желанию. Затем необходимо соответствующим образом изменить ключи id и secondaryId в объекте Item. Я предлагаю не жестко кодировать ни одно из этих значений, как в примерах. Для ключа раздела (id) я предлагаю использовать что-то вроде сгенерированного UUID или значение, уникальное для данных этого элемента. Значение ключа сортировки ( secondaryId) будет больше зависеть от вашей модели данных, но некоторые предложения могут заключаться в использовании сконфигурированного значения, полученного из модуля, переменной среды или значения, специфичного для данных этого элемента.

Если вы мало что знаете о моделировании данных, я настоятельно рекомендую узнать больше и определить, как моделировать данные, прежде чем использовать DynamoDB. Я немного обсуждаю модельный бизнес в этом посте, но есть и другие замечательные ресурсы от Рика Хулихэна (найдите его выступления re:Invent на YouTube) и Алекса ДеБри.

Помните, что это всего лишь примеры, и вы можете изменить свой код по своему усмотрению. Я просто хочу показать, как могут выглядеть вызовы.

Оглавление:

  1. Создание клиента документов
  2. ПутИтем
  3. Пакетная запись
  4. ПолучитьЭлемент
  5. "Запрос"
  6. ОбновитьЭлемент
  7. "Удалить пункт"

Создание клиента документов

Создание Document Client сначала включает в себя создание обычного клиента, а затем инициализацию Document Client с помощью обычного клиента. Мне нравится использовать один модуль, а затем экспортировать клиент для использования в последующих модулях.

const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocument } = require('@aws-sdk/lib-dynamodb');

const client = new DynamoDBClient({
  region: process.env.AWS_REGION,
});

const documentClient = DynamoDBDocument.from(client);

module.exports = {
  documentClient,
};

PutItem

Документация АВС

Создание нового элемента в DynamoDB включает вызов API PutItem или BatchWriteItem. Передается Item, и должны присутствовать раздел и ключ сортировки. Любые дополнительные значения в Item будут записаны как атрибуты.

const myItem = {
  hello: 'world',
  value: 3,
};

await documentClient.put({
  TableName: process.env.TABLE_NAME,
  Item: {
    id: 'myUniqueId',
    secondaryId: 'secondaryId',
    ...myItem,
  },
});

BatchWriteItem

Документация АВС

Этот API был немного более запутанным для меня. Верхний уровень полезной нагрузки содержит ключ RequestItems. Значения для RequestItems — это пары ключ-значение, где ключи — это имена таблиц, а значения — это массивы запросов, отправляемых каждой таблице. Запросы в массивах также являются парами ключ-значение, где ключи — PutRequest или DeleteRequest, а значения — Item (аналогично ) или Key (аналогично DeleteItem) соответственно.

const myItems = [
  {
    hello: 'world',
    value: 3,
  },
  {
    hello: 'mars',
    value: 5,
  },
  {
    hello: 'saturn',
    value: 0,
    rings: true,
  },
];

const requests = [];
myItems.forEach((myItem) => {
  requests.push({
    PutRequest: {
      Item: {
        // Keep in mind that each partition and sort key will need
        // to be unique for each item
        id: 'myUniqueId',
        secondaryId: 'secondaryId',
        ...myItem,
      },
    },
    // Similar payload for DeleteRequest
    // DeleteRequest: {
    //   Key: {
    //     id: 'myUniqueId',
    //     secondaryId: 'secondaryId',
    //   },
    // },
  });
});
const batchWritePayload = {
  RequestItems: {
    [process.env.TABLE_NAME]: requests,
  },
};
await documentClient.batchWrite(batchWritePayload);

GetItem

Документация АВС

Получить предмет довольно просто. Мы передаем раздел и ключ сортировки и получаем ответ, содержащий некоторые метаданные и файл Item.

const res = await documentClient.get({
  TableName: process.env.TABLE_NAME,
  Key: {
    id: 'myUniqueId',
    secondaryId: 'secondaryId',
  },
});
const item = res.Item;

Запрос

Документация АВС

В query есть несколько дополнительных полей, которые на первый взгляд могут показаться запутанными. KeyConditionExpression для query необходимо определить значение ключа раздела и дополнительно можно указать сравнение со значением ключа сортировки. В моем примере ключ сортировки просто сравнивается с равенством (=) со значением (secondaryId), но я мог бы так же легко использовать любое из поддерживаемых ключевых выражений условий.

Следующие запутанные части — это ExpressionAttributeNames и ExpressionAttributeValues. Каждый из них представляет собой способ динамической ссылки на значение в KeyConditionExpression без необходимости подстановки строк. С Document Client это просто, но в некоторых случаях без Document Client нам пришлось бы добавлять типы данных к значениям в ExpressionAttributeValues. Строки, на которые ссылается ExpressionAttributeNames, должны иметь префикс решётки (#), а ExpressionAttributeValues должен начинаться с двоеточия (:). Символы префикса не являются соглашением, они явно указаны в документации.

После того, как результаты собраны из таблицы, мы можем дополнительно уточнить результаты, заставив DynamoDB фильтровать то, что было запрошено с помощью FilterExpression. Это хорошее место, чтобы просмотреть результаты с помощью тонкой гребенки, но просто знайте, что query потребляет единицы запросов на чтение на основе результатов, возвращаемых KeyConditionExpression, а не только результатов, возвращаемых после дальнейшего уточнения с использованием FilterExpression. Опять же, это проблема моделирования данных. FilterExpression использует тот же синтаксис, что и KeyConditionExpression, но может быть записан для любого атрибута в Item.

Наконец, ProjectionExpression — это список атрибутов, разделенных запятыми, которые DynamoDB должна получить и вернуть в результате query. Если бы мы запрашивали элементы из примера BatchWriteItem(#batchwriteitem), мы бы получили hello и value, но не rings.

Мы получаем ответ, содержащий некоторые метаданные, и Items мы сопоставляем KeyConditionExpression и FilterExpression.

const res = await documentClient.query({
  TableName: process.env.TABLE_NAME,
  KeyConditionExpression: 'id = :partitionKey AND secondaryId = :sortKey',
  ExpressionAttributeNames: {
    '#valueName': 'value',
  },
  ExpressionAttributeValues: {
    ':partitionKey': 'myUniqueId',
    ':sortKey': 'secondaryId',
    ':minValue': 3,
  },
  FilterExpression: '#valueName >= :minValue',
  ProjectionExpression: 'hello, value',
});
const items = res.Items;

UpdateItem

Документация АВС

Обновить элемент довольно просто. Мы передаем раздел и ключ сортировки как значение Key, а любые обновления атрибутов — как пары ключ-значение на верхнем уровне полезной нагрузки.

const updates = {
  hello: 'moon',
  value: 300,
};

await documentClient.update({
  TableName: process.env.TABLE_NAME,
  Key: {
    id: 'myUniqueId',
    secondaryId: 'secondaryId',
  },
  ...updates,
});

DeleteItem

Документация АВС

Удаление элемента в DynamoDB включает вызов API DeleteItem или BatchWriteItem. Удаление так же просто, как и получение, мы передаем раздел элемента и ключ сортировки, а DynamoDB обрабатывает все остальное.

await documentClient.delete({
  TableName: process.env.TABLE_NAME,
  Key: {
    id: 'myUniqueId',
    secondaryId: 'secondaryId',
  },
});

Первоначально опубликовано на https://thomasstep.com 20 января 2022 г.

Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Получите эксклюзивный доступ к возможностям написания и советам в нашем сообществе Discord.