Я действительно играл с AppSync / noSQL с тех пор, как обнаружил его. Как разработчику мне нравится контролировать свои инструменты, и у меня есть личная цель - попытаться понять, почему и как вещи созданы для использования. AppSync предоставляет удобный простой инструмент для тестирования и изучения. Он также обеспечивает хороший уровень документированного усложнения, что позволяет мне думать по-разному.

Это стремление к открытиям привело меня к еще одной кладовой информации в иногда огромных документах Amazon. Начиная с этого видео:

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

«Вам следует поддерживать как можно меньше таблиц в приложении DynamoDB. Для большинства хорошо разработанных приложений требуется только одна таблица ».

- Документы AWS

Почему это так сильно выделялось? Ну, я недавно написал статью о добавлении нескольких элементов в несколько баз данных DynamoDB одновременно, найденную здесь. Это было отличное исследование пакетных инструментов и преобразователей кросс-таблиц, но я обнаружил, что задаю несколько разных вопросов.

  1. Если мне нужно выполнить поиск на основе значения в таблице A, как мне вернуть информацию из таблицы B с помощью GraphQL?
  2. Если мне нужно выполнить поиск по одному запросу на основе двух полей, которые используются в таблицах, почему я не использую одну таблицу? Т.е. В таблице A есть поле «заголовок», а в таблице B - поле «заголовок».
  3. Есть ли способ создавать и возвращать разные аспекты одной таблицы в одних и тех же запросах graphQL?

Принятие решения изучить эти вопросы сорвало рабочий процесс моего проекта, но в целом это принесло пользу. Итак, вот окончательный результат последнего глубокого погружения в управление данными DynamoDB + GraphQL +.

Я буду продолжать использовать Рецепт в качестве своего имитационного объекта.

Организация данных

В модели с несколькими столами у меня была таблица для каждой части рецепта. Рецепт, элементы рецепта и ингредиенты.

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

Теперь я использую один первичный ключ раздела для всех частей рецепта, используя первичный ключ сортировки, чтобы различать разные части.

У рецепта есть идентификатор:

87971.

Вся высокоуровневая информация о рецепте хранится в виде идентификатора:

recipe87971: info1.

Каждый элемент хранится в виде идентификатора:

recipe87971: element1.

Каждый ингредиент хранится в виде идентификатора относительно его родительского элемента:

recipe87971: element1: component1.

Все части рецепта могут быть немедленно загружены, зная только идентификатор родительского рецепта! Это отличается от поиска по нескольким таблицам тем, что я выполняю один запрос на чтение. Поскольку все они расположены рядом друг с другом, гипотетически это могло бы использовать преимущества Amazon.

Определение схемы

Определение схемы не меняется слишком сильно между моделями. Одно небольшое изменение, которое я заметил, заключается в том, что вложенные элементы, живущие все в одной таблице, теперь должны иметь ссылку в родительском объекте, который будет вызван. Таким образом, мой тип рецепта выглядит следующим образом:

type Recipe {
  id: ID!
  type: ID!
  title: String!
  category: String
  dbtype: String
  status: String
  elements: [Element]
  ingredients: [Ingredient]
}
  • В моей предыдущей итерации ingredients жил только с типом Element.

Большим изменением в этом определении схемы является возврат запросов. Именно здесь я сильнее ощущаю присутствие GraphQL. Допустим, я просматриваю список названий рецептов + краткое описание, а затем нахожу рецепт, который хочу проверить. Пользователь может щелкнуть элемент, а затем, используя его идентификатор, мы можем запросить и скомпилировать данные нужным образом.

type RecipeBuild {
  id: ID
  category: String
  elements: [Recipe]
  title: String
  type: String
  status: String
}

Ингредиенты не нужно открывать напрямую, потому что с этим можно справиться в нашем преобразователе. Это работает, потому что мы не возвращаем ни одного элемента при поиске по идентификатору рецепта. Мы находим детали, которые можем потреблять по своему желанию.

Шаблоны картографии

Теперь, когда у нас есть детали, нам просто нужно определить, как мы будем с ними работать.

Наш шаблон запроса остается простым, запрос по идентификатору. Если в ответ не было внесено никаких изменений, мы получили бы базовый список с элементом массива для каждого элемента с идентификатором.

Но мы этого не хотим. Для внешнего интерфейса нам нужно убедиться, что данные организованы для визуализации. Информация высокого уровня отделена от вложенных элементов. Это позволит нам map по каждому элементу, а также по каждому ингредиенту, содержащемуся в элементах. В конечном итоге было бы неплохо что-то вроде этого:

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

Происходит несколько вещей.

  • Каждый элемент просматривается и, в зависимости от его типа, помещается в массив или сохраняется как переменная.
  • Информация высокого уровня возвращается как атрибут карты
  • Элементам предоставляется их собственный массив, который будет возвращен как атрибут возвращаемой карты.
  • Ингредиенты хранятся в собственном массиве для дальнейшей итерации.
  • Ингредиенты, основанные на их elementId, затем сохраняются в правильном элементе для повторения позже. Примечание. Вы заметите, что мы не отображаем массив Ingredients напрямую на карте. Это потому, что это карта и работает как JSON, поэтому нам не нужно.

Этот шаблон сопоставления ответов возвращает следующее при поиске определенного идентификатора рецепта блинов:

Не потрепать а! Это в дополнение к пакетному добавлению записей db должно поддерживать довольно низкую потребляемую емкость чтения / записи. Однако я не смогу проверить это, пока не интегрирую эту новую модель данных в мой клиент Apollo / React. Скорее всего, я напишу об этом в следующий раз!