Обработка данных с возможностью масштабирования часто бывает довольно сложной. Когда App Engine был запущен, он предлагал масштабируемость как на стороне сервера приложений за счет автоматического управления экземплярами, так и на стороне базы данных, предоставляя решение NoSQL под названием Datastore. Со временем хранилище данных стало отдельным продуктом под названием Cloud Datastore, который теперь доступен за пределами экземпляров App Engine.

У нас есть немалая история использования Datastore в наших проектах App Engine: на Java-бэкэнде Easyling или в нашем полнофункциональном приложении Dart под названием Gyerünk anyukám! (Примерно переводится как Go, Mommy, Go! ), Который мы недавно портировали на Dart 2.0 . Это было зарекомендовало себя как довольно мощное и удобное решение для ваших баз данных с масштабированием и обслуживанием, которое мы сделали за нас. В следующей серии статей я объясню основы базы данных и покажу решения проблем, с которыми я сталкивался на протяжении многих лет.

Когда мне приходилось обращаться к Cloud Datastore из Dart, доступные библиотеки были либо слишком сложными, либо намного отставали от того, что Datastore может делать сейчас. Итак, я выбрал сложное решение и написал фасад, который упростит вещи без ущерба для функциональности и открыт для будущих разработок, сделав использование фасада совершенно необязательным. Эта библиотека называется entify, и она доступна в пабе.

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

Сейчас мы будем использовать эмулятор хранилища данных, для которого вам нужно сначала установить Google Cloud SDK. После того, как вы закончите, вы можете попробовать запустить эмулятор хранилища данных, команда автоматически установит компонент, когда вы попытаетесь запустить его в первый раз:

gcloud beta emulators datastore start --project=tutorial --data-dir=datastore-emulated

Это создаст каталог с именем datastore-emulated в текущем каталоге и поместит туда свои файлы. Название проекта будет tutorial, можете заменить его своим собственным, но не забудьте заменить их позже, когда мы будем ссылаться на проект в коде Dart.

Начнем с написания pubspec.yaml:

Пакет entify упрощает работу с хранилищем данных без потери функциональности. Он основан на классе DatastoreShell, который обеспечивает тонкий, но мощный фасад над классом DatastoreApi googleapi. Поэтому для доступа к функциямentify нам понадобится DatastoreApi экземпляр:

На данный момент этого достаточно, он будет работать с эмулятором, но объект http.Client должен быть аутентифицированным клиентом, когда мы собираемся получить доступ к Cloud Datastore. Теперь мы можем создать экземпляр объекта aDatastoreShell:

Затем мы можем сохранить несколько сущностей:

Entity очень похож на рекорд в мире SQL с некоторыми отличиями. Сначала ключ имеет следующие свойства:

  • у каждого ключа есть поле вида, которое определяет тип объекта, как и имена таблиц.
  • ключ может иметь имя (строка, не длиннее 1500 байтов UTF-8) или идентификатор (положительное 64-битное целое число)
  • ключи могут иметь родительский ключ, который может пригодиться в транзакциях, он требует немного большего объяснения и понимания системы, поэтому он будет подробно объяснен позже, до тех пор я бы посоветовал не использовать его

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

  • null
  • int (64 бит)
  • double
  • bool
  • String: ограничено 1500 байтами UTF-8 при индексировании
  • blob: смоделировано с Uint8List
  • Key: значения могут быть ключами хранилища данных
  • List: значения любого типа из вышеперечисленного (и не обязательно однородные)

Размер объекта не может превышать 1 МБ.

DateTime значения отсутствуют в поддерживаемых типах, и причина в том, что мы всегда находили, что лучший способ их хранения - это хранить метки времени в стиле Javascript (другими словами millisecondsSinceEpoch). Эти временные метки всегда однозначны, мы еще не нашли случая, когда они не применимы.

При первом запуске программы объект будет вставлен и успешно завершится. Но запустив его во второй раз, мы получим исключение о том, что объект уже существует. Экземпляр MutationBatch, возвращаемый beginMutation(), поддерживает следующие методы мутации:

  • insert: создать объект, если он не существует, сбой, если уже существует объект с таким же ключом
  • update: обновить уже существующий объект с помощью ключа, сбой, если он не существует
  • upsert: либо update, либо insert сущность в хранилище данных в зависимости от того, существует ли сущность с ключом или нет, поэтому обычно она никогда не должна выходить из строя
  • delete: удалить сущность с ключом

У каждого метода есть версия, которая принимает Iterable сущностей или ключей: insertAll, updateAll, upsertAll, delete.

Заменим функции insertAnEntity и main:

На этот раз он пытается прочитать объект, если объект существует, он печатает разницу во времени и выполняет обновление, в противном случае он просто вставляет объект.