EJDB

Материал из Национальной библиотеки им. Н. Э. Баумана
EJDB
Ejdb-2.png
Создатели: Антон Адаманский
Разработчики:

группа программистов во главе с Антоном Адаманским

Россия
Выпущена: 2012 год (EJDB1.0)
Постоянный выпуск: 2.0 (Core) / апрель 2018 года
Состояние разработки: Активно
Написана на: Java
Операционная система: кросс-платформенная
Локализация: English
Тип ПО:

Встроенная база данных JSON

Объектно-ориентированная СУБД
Лицензия: MIT
Веб-сайт ejdb.org

EJDB (Embedded JSON DataBase engine) - это встроенная база данных JSON, основанная на модифицированной версии Tokyo Cabinet. EJDB нацелена на создание быстрой библиотеки, подобной MongoDB, которая может быть встроена в приложения C / C ++. [Источник 1] Он включает блокировку записи на уровне коллекции, транзакции на уровне коллекции, запросы на сопоставление с токеном строки и привязку Node.js. Представление JSON объектов, реализовано с помощью API на основе C BSON.

Содержание

История

Основателем проекта стал разработчик и преподаватель НГУ[Источник 2] Антон Адаманский[Источник 3]. Всё началось в 2011 году, изначально возникла идея о создании удобной системы хранения информации и поиска метатегов аудиофайлов для небольшого медиаплеера, написанной на C++. Но во время осуществления задуманного возникли следующие проблемы: реализация была слишком громоздкой ( SQLite ) или имела проблемы со стабильностью ( GigaBASE ); размер всего проекта составлял одну десятую от одного файла sqlite.c (тогда Антон не сравнивал размер проекта с ядром системы). Как говорил сам автор : "2011 год был золотым веком различных решений NoSQL". Помимо этого рассматривалась MongoDB, как возможное решение, но в процессе изучения выявились два существенными ограничения:

  1. Трудность использования MongoDB в качестве дополнительной DLL, потому что изначально ее разработчики не планировали такой вариант применения, а MongoDB технически не был готов к этому.
  2. MongoDB был под лицензией AGPL, что,на тот момент только вредило проекту. По словам Антона Адаманского AGPL ничего не приносит в мир открытого программного обеспечения и, как правило, было удобным прикрытием для коммерческих лицензированных продуктов с условно-бесплатным кодом.

Тогда в поисках лучшего варианта облегченной системы хранения данных для небольших проектов были определены ключевые качества продукта:

  • Документно-ориентированность с возможностью хранения иерархии документов с произвольной структурой.
  • Поддержка коллекций документов JSON.
  • Реализовано на языке C99.
  • Бесплатная лицензия, которая позволяет использовать продукты с закрытым исходным кодом.

Вдохновившись MongoDB была создана система управления базами данных(в дальнейшем СУБД), реализованная в виде разделяемой библиотеки ( EJDB 1.0 ). EJDB 1.0 основан на модифицированной версии проекта TokyoCabinet,который на данный момент уже заброшен. EJDB стал довольно популярным на github [Источник 4] среди разработчиков со всего мира. Тогда один из менеджеров 10gen связался с разработчиками, чтобы обсудить совместимость запросов между EJDB и MongoDB, но после обсуждения вопросы о сотрудничестве больше не поступали.Однако разработчики взяли слишком много у MongoDB, что и стало проблемой, так к примеру, громоздкий формат поисковых запросов. Другим спорным элементом, взятым из MongoDB, стала функция, которая сохраняла первичный ключ документа в самом документе, как специальное поле _id, которое смешивает исходную структуру хранимого документа с реализацией системы хранения. Позднее TokyoCabinet, наложил лицензию LGPL 1.x на EJDB, которая является более свободной, чем AGPL, но все же ограничивает использование EJDB во многих проектах.Будучи немного разочарованными, разработчики выпустили несколько версий EJDB, а затем оставили его неактивным в течение нескольких лет. В 2018 году проанализировав современный IT рынок и технологии было принято решение о создании второй версии EJDB, главным девизом которой стал лозунг "Хватит Усложнять!". EJDB 2.0 полностью избавились от кода LGPL из TokyoCabinet. Исходный код стал полностью открытым благодаря использованию лицензии MIT для всех компонентов проекта. Для EJDB2 было разработано хранилище данных Key-value под лицензией MIT[Источник 5]. Описание хранилища iowow смотрите ниже.

Архитектура EJDB

Как говорилось ранее EJDB является встраиваемой кроссплатформенной документо-ориентированной (иерархической, в англоязычной литературе document-oriented)[Источник 6] СУБД для JSON данных, которая представлет собой разделяемую библиотеку для windows/linux платформ. Самые популярные СУБД для работы с JSON данными – это mongodb и couchdb, но они работают с использованием протокола TCP/IP. Такой подход очень удобен в реализации серверных приложений, однако не слишком пригоден для встраивания базы в легкие приложения, такие как мобильные приложения и проч., по следующим причинам:

  • скорость общения клиента с базой данных через протокол TCP/IP значительно медленнее, чем скорость того же общения, работающего через разделяемую память в адресном пространстве запущенного процесса;
  • во время развертывания программного продукта в конечной среде можно столкнуться с рядом препятствий. Эти трудности приходят из необходимости одновременного развертывания продукта с СУБД. Таким образом, мы должны установить систему управления базой данных как отдельный сетевой сервис. Эта конфигурация более сложная для поддержки, а также может создавать уязвимости в безопасности программы.

Основой EJDB является общая философия MongoDB и язык запросов этой СУБД. Реализация EJDB технически основывается на tokyocabinet 2 – хранилище данных типа ключ-значение, которое распространяется под лицензией LGPL (Lesser GNU Public License). Система хранения EJDB построена на низкоуровневых структурах данных, которые предоставляет tokyocabinet:

  • B+ дерево (tcbdb);
  • хеш-таблица, которая хранит записи вида ключ-значение (tchdb);
  • табличная база данных (tctdb)

Внутри EJDB JSON документы представлены как BSON (Binary JSON) объекты. Этот формат достаточно компактный и эффективный для хранения и обработки данных. EJDB хранит набор коллекций, где каждая коллекция содержит набор логически связанных документов JSON. Логически каждая коллекция EJDB – это табличная база данных tokyocabinet (tctdb), которая явлется хранилищем таблиц, не зависимых от схемы с записаннымданными в строки, разделенные на набор определенных пользователем колонок. Таблица структуры документа JSON, представлена ниже:

столбец первичного ключа cтолбец документа BSON столбец метаданных документа
Первичный ключ UUID 12 байт Тело документа BSON атрибуты безопасности документов, статистика доступа и т. д

Каждая строка таблицы разделена на три части: 24-битный уникальный идентификатор, тело документа в формате BSON и дополнительные метаданные документа. Если документы не содержат проиндексированные поля в процессе выполнения запроса, вся коллекция документов будет просканирована, и BSON-документы, чьи поля подошли к запросу, будут выбраны. Выбор документа по первичному ключу сводится к выборке записей данных с диска при помощи хэш-таблицы. Эта операция может быть выполнена достаточно быстро. EJDB-запросы определены как набор CRUD-операций с документами, хранящимися в коллекциях, т. е. создание, чтение, обновление и удаление. Правила CRUD представлены в виде набора BSON-документов, состав которых похож на запросы MongoDB. CRUD-операции чтения определяют набор ограничений на поля, применяемых к коллекции документов. Так как структура JSON-документов может быть иерархичной, то fieldpath используется для идентификации документа. Например, условие запроса на выбор книг с определенным издателем может быть таким: {"publisher.name" : "some publisher"}. EJDB стремится быть совместимой с MongoDB в плане запросов, так как это обеспечит возможность легкой миграции приложений из/в MongoDB. На данный момент около 70 % запросов mongodb реализованы в EJDB, планируется достигнуть совместимости по запросам в 90 %. Кроме того, EJDB расширяет возможности запросов MongoDB и предоставляет следующие возможности извлечения данных:

  • оптимизированное сравнение строк, не зависящее от регистра;
  • быстрое сравнение строк, например, запрос {"words" : {"$strand" : ["one", "two"]}} находит докумнты, где строковое поле words содержит слова «one» и «two» в наборе из слов,разделенных пробелами.
  • оптимизированный строковый префикс matching with "$begin";
  • соединение набора документов. Вхождения документов в различные коллекции могут

быть объединены с помощью первичного ключа, как результат одного запроса. Если разработчик захочет получить объединение объектов из связанных коллекций, ему придется исполнить как минимум N + 1 запрос, где N – это количество элементов основной коллекции. Для того чтобы ликвидировать эти тривиальные раунды, EJDB предлагает способ указатьобъединение как часть исполнения одного запроса в следующей формой: "{$do : {<fpath> :{$join : <collection name>}}}", где <fpath> – это путь к полю документа, содержащего идентификаторы объектов, которые будут объединены с другой коллекцией.

Iowow

Хранилище Iowow [Источник 7] может работать со многими базами данных «ключ-значение», хранящимися в одном файле, что упрощает передачу данных между устройствами и создание резервных копий, а также снижает вероятность несоответствий в данных находящихся в нём. Iowow основан на простой структуре данных - списке пропусков , что позволило нам создать гораздо более понятную реализацию постоянного хранилища с гораздо меньшей базой кода (по сравнению с деревом B + и деревом LSM) с высокой производительностью (в соответствии с тестами). Максимальный объем файла базы данных составляет 512 ГБ, что является следствием компромиссов при реализации однофайловой базы данных в списках пропуска. Документы, хранящиеся в коллекциях EJDB2, сериализуются в простом двоичном формате - Binn.

Структура данных EJDB

Физически EJDB [Источник 8] это:

  • Мета-файл в котором хранится информация об доступных коллекциях. Это табличная база tctdb.
  • Для каждой коллекции:
  • Мета-файл с данными об индексах коллекции и настройках коллекции (tctdb)
  • Файл c данными JSON объектов коллекции (tctdb)
  • Набор B-Tree индексов для полей JSON объектов (tcbdb)

JSON объекты в EJDB представлены в формате BSON (Binary JSON). Для работы с BSON используется несколько модифицированная версия BSON API из C драйвера mongodb (ссылка). Стоит заметить, что BSON очень эффективный формат для представления любых иерархических данных со строковыми ключами и типизированными значениями как с точки зрения удобства навигации так и производительности, и отлично может подойти для внутреннего представления данных в обычных С/C++ программах.

Записи в коллекции EJDB хранятся в табличной базе tctdb. База tctcdb является хеш-таблицей, где значение каждой записи это словарь в котором ключ (c1..cN) это имя колонки в таблице, и соответствующие им данные (v1..vN). Каждая запись в табличной базе может иметь свой набор колонок. Данные разных записей принадлежащие к колонкам с одинаковым именами могут быть проиндексированы в B+ дереве tcbdb ссылаясь на первичные ключи основной хеш таблицы.

В качестве первичных ключей используются уникальные двенадцатибайтные идентификаторы UUID для JSON объектов. Объекты сериализованные в BSON формат хранятся в колонке с кратким и звучным именем $. Подобная модель допускает возможность связи произвольной мета информации с записями коллекции, путем добавления новых колонок, например списков доступа (ACL) на уровне записей, или данных статистики доступа к записям, но оставим это для следующих релизов.

Какая требовалась функциональность от этой библиотеки:

  • Хранение коллекций JSON объектов
  • Mongodb-like запросы относительно коллекций
  • Поддержка транзакций на уровне коллекций
  • Связка с NodeJS

Что было использовано из tokyocabinet:

  • B+ деревья (tcbdb.h)
  • Хеш таблицы (tchdb.h)
  • Табличная база (tctdb.h)
  • Структуры данных и утилиты (tcutil.h)

В этом списке в скобках приведены ссылки на элементы api tokyocabinet. [Источник 9]

Работа с EJDB

В данном разделе приводятся необходимые действия для установки библиотеки для работы с базой данных EJDB на разных платформах (macOS / OSX, Linux Ubuntu / Debian, Windows), а также пример приложения для подключения к базе данных EJDB, ее заполнения простым набором данных и поиска записей среди них, написанного на языках программирования C, Java, JavaScript (Node.js), Dart и Swift. Наиболее подробно рассмотрен вариант запуска приложения на языке Java с библиотекой EJDB на платформе macOS.

1. Установка библиотеки для работы с базой данных EJDB

1.1 macOS / OSX Для работы с библиотекой из терминала достаточно воспользоваться командой:

% brew install ejdb

Здесь используется менеджер пакетов для macOS - Homebrew, установка которого также выполняется одной командой:

% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/ma..)"

Также доступны другие способы установки Homebrew, которые описаны на официальном сайте https://brew.sh/index_ru Установка библиотеки для ее использования в коде выполняется следующими командами:

% git clone https://github.com/Softmotions/ejdb.git
cd ./ejdb
mkdir ./build && cd build
cmake .. -DBUILD_JNI_BINDING=ON -DCMAKE_BUILD_TYPE=Release
make

1.2 Linux Ubuntu / Debian

1.3 Windows Библиотека может быть установлена с использованием кроссплатформенной системы автоматизации сборки программного обеспечения из исходного кода CMake (https://github.com/Softmotions/ejdb/blob/master/WINDO..). Однако наиболее простым способом является развертывание библиотеки с помощью программного обеспечения для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации - Docker. Для этого необходимо установить само программное обеспечение Docker, скачав установщик с официального сайта https://www.docker.com/products/docker-desktop и проследовав стандартным пунктам установки.






Чтобы начать работать с EJDB нам нужно перейти на сайт:https://ejdb.org (он полостью англоязычный). На нём регистрироваться не нужно!

Знакомство с EJDB

Далее мы видим что на сайте уже есть необходимое разбиение по разделам. При желании можно сразу нажать на нужный раздел и вы перейдёте на этот же раздел на GitHub. Или можно перейти по расположенной сверху ссылке сразу на весь GitHub[Источник 10]. Перейдя по ссылке мы увидим всю необходимую информацию для работы с библиотекой:

GitHub EJDB2.0

Информация и сама версия EJDB2.0. постоянно обновляется автором.


EJDB 2.0

EJDB2 - это встраиваемый движок базы данных JSON, опубликованный под лицензией MIT.

  • C11 API
  • Однофайловая база данных
  • Онлайн поддержка резервного копирования
  • Размер библиотеки 500K для Android
  • iOS / Android / React Native / Flutter интеграция
  • Простой, но мощный язык запросов (JQL), а также поддержка следующих стандартов:
  1. rfc6902 JSON Patch
  2. rfc7386 JSON Merge patch
  3. rfc6901 JSON Path
  • Поддержка коллекционных объединений
  • Работает на owow.io - механизм постоянного хранения ключей / значений
  • Предоставляет конечные точки сети HTTP REST / Websockets с помощью facil.io
  • Документы JSON хранятся в быстром и компактном двоичном формате
  • Привязки родного языка

Матрица платформ EJDB2

Linux macOS iOS Android Windows
Библиотека С ✔️ ✔️ ✔️ ✔️ ✔️1
NodeJS ✔️ ✔️ ❌3
DartVM ✔️ ✔️2 ❌3
Flutter ✔️ ✔️
React Native ❌4 ✔️
Swift ✔️ ✔️ ✔️
Java ✔️ ✔️ ✔️ ✔️2
  1. Нет поддержки HTTP / Websocket # 257[Источник 11]
  2. Двоичные файлы не распространяются с dart pub. Но его можно построить вручную.[Источник 12]
  3. Можно построить, но нужна связь с windows node / dart libs.
  4. Выполняется перенос # 273[Источник 13]

Привязки родного языка

  • NodeJS
  • Dart
  • Java
  • Android support
  • Swift | iOS
  • React Native
  • Flutter

Неофициальные привязки к родному языку

  • .Net
  1. https://github.com/kmvi/ejdb2-csharp
  • Haskell
  1. https://github.com/cescobaz/ejdb2haskell
  2. https://hackage.haskell.org/package/ejdb2-binding
  • Pharo
  1. https://github.com/pharo-nosql/pharo-ejdb

Статус

  • Ядро EJDB 2.0 хорошо протестировано и используется в различных сильно загруженных средах.
  • Протестировано на платформах Linux и OSX. Ограниченная поддержка Windows[Источник 14]
  • Старая версия EJDB 1.x находится в отдельной ветке ejdb_1.x на GitHub, но она не поддерживается.

Случаи использования

  • Softmotions платформа для торговых роботов
  • Gimme - социальная игра для обмена токенами мобильного приложения. EJDB2 используется как на стороне мобильного телефона, так и на стороне сервера.

macOS / OSX

Код EJDB2 перенесен и протестирован на High Sierra / Mojave / Catalina

См. Также EJDB2 Swift[Источник 15] для OSX, iOS и Linux.

brew install ejdb

или

mkdir build && cd build
 cmake .. -DCMAKE_BUILD_TYPE=Release
 make install 

Linux

Ubuntu/Debian

PPA хранилище

 sudo add-apt-repository ppa:adamansky/ejdb2
 sudo apt-get update
 sudo apt-get install ejdb2

Сборка пакетов Debian требуется cmake v3.15 или выше

mkdir build && cd build
 cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_DEB=ON
 make package

Дистрибутивы Linux на основе RPM

mkdir build && cd build
 cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_RPM=ON
 make package


Windows

EJDB2 может быть скомпилирован для Windows Сетевой API HTTP / Websocket отключен и не поддерживается в Windows для порта библиотеки http://facil.io (# 257) Привязки Nodejs / Dart еще не перенесены в Windows.

Руководство по кросс-компиляции для Windows.[Источник 16]

Android


Пример приложения для Android

JQL

Синтаксис языка запросов EJDB (JQL), основанный на идеях, лежащих в основе оболочек XPath и Unix. Он предназначен для удобного запроса и обновления наборов документов JSON.

Грамматика JQL

Парсер JQL создан с помощью peg / leg - генераторов парсеров рекурсивного спуска для C. Вот формальная грамматика парсера: https://github.com/Softmotions/ejdb/blob/master/src/jql/jqp.leg

Неформальная грамматика JQL адаптированная для краткого обзора

Используемая ниже запись основана на описании синтаксиса SQL:

Правила описание
' ' Строка в одинарных кавычках обозначает строковый литерал без кавычек как часть запроса.
{ a Вертикальная черта b } Фигурные скобки заключают в себя два или более обязательных альтернативных варианта, разделенных вертикальной чертой.
[ ] Квадратные скобки указывают на необязательный элемент или предложение. Несколько элементов или предложений разделены вертикальными чертами.
Вертикальная черта Вертикальные черты разделяют два или более альтернативных синтаксических элементов.
... Точки указывают, что предыдущий элемент может быть повторен. Повторение не ограничено, если не указано иное.
( ) Круглые скобки являются символами группировки.
Слово без кавычек в нижнем регистре Обозначает семантику некоторой части запроса. Например: placeholder_name - имя любого заполнителя.

QUERY = FILTERS [ '|' APPLY ] [ '|' PROJECTIONS ] [ '|' OPTS ];

STR = { quoted_string | unquoted_string };

JSONVAL = json_value;

PLACEHOLDER = { ':'placeholder_name | '?' }

FILTERS = FILTER [{ and | or } [ not ] FILTER];

  FILTER = [@collection_name]/NODE[/NODE]...;

  NODE = { '*' | '**' | NODE_EXPRESSION | STR };

  NODE_EXPRESSION = '[' NODE_EXPR_LEFT OP NODE_EXPR_RIGHT ']'
                        [{ and | or } [ not ] NODE_EXPRESSION]...;

  OP =   [ '!' ] { '=' | '>=' | '<=' | '>' | '<' }
      | [ '!' ] { 'eq' | 'gte' | 'lte' | 'gt' | 'lt' }
      | [ not ] { 'in' | 'ni' | 're' };

  NODE_EXPR_LEFT = { '*' | '**' | STR | NODE_KEY_EXPR };

  NODE_KEY_EXPR = '[' '*' OP NODE_EXPR_RIGHT ']'

  NODE_EXPR_RIGHT =  JSONVAL | STR | PLACEHOLDER

APPLY = 'apply' { PLACEHOLDER | json_object | json_array  } | 'del'

OPTS = { 'skip' n | 'limit' n | 'count' | 'noidx' | 'inverse' | ORDERBY }...

  ORDERBY = { 'asc' | 'desc' } PLACEHOLDER | json_path

PROJECTIONS = PROJECTION [ {'+' | '-'} PROJECTION ]

  PROJECTION = 'all' | json_path
  • json_value: любое допустимое значение JSON: объект, массив, строка, bool, число.
  • json_path: упрощенный указатель JSON. Например: / foo / bar или / foo / "bar с пробелами" /
  • * в контексте NODE: любое имя ключа объекта JSON на определенном уровне вложенности.
  • ** в контексте NODE: любое имя ключа объекта JSON на произвольном уровне вложенности.
  • * в контексте NODE_EXPR_LEFT: имя ключа на определенном уровне.
  • ** в контексте NODE_EXPR_LEFT: значение вложенного массива элемента массива под конкретным ключом.

Краткое описание JQL

Для простоты мы будем использовать сетевой API ejdb websocket, который предоставляет нам своего рода интерактивный CLI. То же самое можно сделать и с использованием чистого C API (ejdb2.h jql.h).

ПРИМЕЧАНИЕ. Просмотрите примеры тестов JQL для получения дополнительных примеров.[Источник 19]

 {
   "firstName": "John",
   "lastName": "Doe",
   "age": 28,
   "pets": [
     {"name": "Rexy rex", "kind": "dog", "likes": ["bones", "jumping", "toys"]},
     {"name": "Grenny", "kind": "parrot", "likes": ["green color", "night", "toys"]}
   ]
 }

Сохраните json как sample.json и загрузите family coolection:


 # Start HTTP/WS server protected by some access token
 ./jbs -a 'myaccess01'
 8 Mar 16:15:58.601 INFO: HTTP/WS endpoint at localhost:9191

Доступ к серверу можно получить через конечную точку HTTP или Websocket. Больше информации[Источник 20]:

curl -d '@sample.json' -H'X-Access-Token:myaccess01' -X POST http://localhost:9191/family


Мы можем поиграть, используя интерактивный клиент wscat websocket[Источник 21].

 wscat  -H 'X-Access-Token:myaccess01' -q -c http://localhost:9191
 connected (press CTRL+C to quit)
 > k info
 < k     {
  "version": "2.0.0",
  "file": "db.jb",
  "size": 8192,
  "collections": [
   {
    "name": "family",
    "dbid": 3,
    "rnum": 1,
    "indexes": []
   }
  ]
 }
 
 > k get family 1
 < k     1       {
  "firstName": "John",
  "lastName": "Doe",
  "age": 28,
  "pets": [
   {
    "name": "Rexy rex",
    "kind": "dog",
    "likes": [
     "bones",
     "jumping",
     "toys"
    ]
   },
   {
    "name": "Grenny",
    "kind": "parrot",
    "likes": [
     "green color",
     "night",
     "toys"
    ]
   }
  ]
 }

Примечание о префиксе k - это произвольный ключ, выбранный клиентом и предназначенный для идентификации конкретного запроса веб-сокета. Этот ключ будет возвращен в ответ на запрос и позволяет клиенту идентифицировать этот ответ для своего конкретного запроса.[Источник 22]

Команда запроса через websocket имеет следующий формат:

<key> query <collection> <query>

Поэтому мы рассмотрим только часть <query> в этом документе.

Получение всех элементов в коллекции

k query family /*

или

k query family /**

или указать имя коллекции в запросе явно

 k @family/*

Мы можем выполнить запрос по запросу HTTP POST

curl --data-raw '@family/[firstName=John]' -H'X-Access-Token:myaccess01' -X POST http://localhost:9191
 1	{"firstName":"John","lastName":"Doe","age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]},{"name":"Grenny","kind":"parrot","likes":["green color","night","toys"]}]}

Установка максимального количества элементов в наборе результатов

k @family/* | limit 10

Получение документов, в которых существует указанный путь json

Элемент с индексом 1 существует в массиве likes в подобъекте pets


 > k query family /pets/*/likes/1
 < k     1       {"firstName":"John"...

Элемент с индексом 1 существует в массиве likes на любом уровне вложенности likes


 > k query family /**/likes/1
 < k     1       {"firstName":"John"...

С этого момента и ниже я опущу семейство запросов с префиксом k для веб-сокетов и рассмотрю только JQL-запросы.

Получение документов по первичному ключу

Для получения документов по первичному ключу доступны следующие опции:

  1. Использовать вызов API ejdb_get ()
 const doc = await db.get('users', 112);
  1. Используйте специальную конструкцию запроса: / = :? или @ collection / = :?

Получение документов из коллекции пользователей с первичным ключом 112

> k @users/=112

Обновление массива тегов для документа в коллекции заданий (TypeScript):

  await db.createQuery('@jobs/ = :? | apply :? | count')
    .setNumber(0, id)
    .setJSON(1, { tags })
    .completionPromise();

Массив первичных ключей также можно использовать для сопоставления:

  await db.createQuery('@jobs/ = :?| apply :? | count')
    .setJSON(0, [23, 1, 2])
    .setJSON(1, { tags })
    .completionPromise();

Соответствующие значения записи JSON

Ниже приведен набор самоочевидных запросов:


 /pets/*/[name = "Rexy rex"]

 /pets/*/[name eq "Rexy rex"]

 /pets/*/[name = "Rexy rex" or name = Grenny]

Обратите внимание на кавычки вокруг слов с пробелами.

Получить все документы, где владелец старше 20 лет, и есть домашнее животное, которое like bones или toys

/[age > 20] and /pets/*/likes/[** in ["bones", "toys"]]

Здесь ** обозначает некоторый элемент в массиве likes.

ni - обратный оператор для in. Получить документы, где bones находится где-то в массиве likes.

/pets/*/[likes ni "bones"]

Мы можем создавать более сложные фильтры


 ( /[age <= 20] or /[lastName re "Do.*"] )
  and /pets/*/likes/[** in ["bones", "toys"]]

Сопоставление массивов и контейнеров map

Фильтрация документов по массиву likes, точно совпадающему с ["bones","jumping","toys"]

/**/[likes = ["bones","jumping","toys"]]

Алгоритмы сопоставления для массивов и карт различны:

  • Элементы массива сопоставляются от начала до конца. В равных массивах все значения с одинаковым индексом должны быть равны.
  • Сопоставление карт объектов состоит из следующих этапов:
  1. Лексикографически сортируйте ключи объекта на обеих картах.
  2. Выполните сопоставление ключей и их значений, начиная с самого низкого ключа.
  3. Если все соответствующие ключи и значения в одной карте полностью совпадают с ключами в другой и наоборот, карты считаются равными. Например: {"f": "d", "e": "j"} и {"e": "j", "f": "d"} являются равными картами.

Условия по ключевым именам

Нахождение документа JSON с ключом firstName на корневом уровне.

/[* = "firstName"]

В этом контексте * обозначает имя ключа.

Вы можете использовать условия для имени ключа и значения ключа одновременно:

 /[[* = "firstName"] = John]

Имя ключа может быть firstName или lastName, но в любом случае должно иметь значение John.

/[[* in ["firstName", "lastName"]] = John]

Это может быть полезно в запросах с динамическими заполнителями (C API):

/[[* = :keyName] = :keyValue]

Модификация данных JQL

APPLY раздел, отвечающий за изменение содержания документов.

APPLY = ('apply' { PLACEHOLDER | json_object | json_array  }) | 'del'


Спецификации патча JSON соответствуют спецификациям rfc7386 или rfc6902, после которых следует ключевое слово apply.

Давайте добавим объект address ко всему найденному документу

/[firstName=John] | apply {"address":{"city":"New York", "street":""}}

Если объект JSON является аргументом секции apply, он будет рассматриваться как совпадение слиянием (rfc7386), в противном случае это должен быть массив, обозначающий патч JSON rfc6902. Заполнители также поддерживаются разделом заявки.

 /* | apply :?

Установите название улицы в address

/[firstName=John] | apply [{"op":"replace", "path":"/address/street", "value":"Fifth Avenue"}]

Добавьте Neo fish в набор pets Джона


 /[firstName=John]
 | apply [{"op":"add", "path":"/pets/-", "value": {"name":"Neo", "kind":"fish"}}]

Нестандартные расширения патча JSON

increment

Увеличивает числовое значение, определяемое путем JSON, на указанное значение.

Пример:


 Document:  {"foo": 1}
 Patch:     [{"op": "increment", "path": "/foo", "value": 2}]
 Result:    {"foo": 3}

'''add_create'''

То же, что и добавление исправления JSON, но создает промежуточные узлы объекта для отсутствующих сегментов пути JSON.

Пример:


 Document: {"foo": {"bar": 1}}
 Patch:    [{"op": "add_create", "path": "/foo/zaz/gaz", "value": 22}]
 Result:   {"foo":{"bar":1,"zaz":{"gaz":22}}}

Пример:


 Document: {"foo": {"bar": 1}}
 Patch:    [{"op": "add_create", "path": "/foo/bar/gaz", "value": 22}]
 Result:   Error since element pointed by /foo/bar is not an object

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

Используйте ключевое слово del, чтобы удалить соответствующие элементы из коллекции:

/FILTERS | del

Пример:


 > k add family {"firstName":"Jack"}
 < k     2
 > k query family /[firstName re "Ja.*"]
 < k     2       {"firstName":"Jack"}

 # Remove selected elements from collection
 > k query family /[firstName=Jack] | del
 < k     2       {"firstName":"Jack"}

JQL проекции


 PROJECTIONS = PROJECTION [ {'+' | '-'} PROJECTION ]
 PROJECTION = 'all' | json_path | join_clause

Проекция позволяет получить только подмножество JSON-документа, исключая ненужные данные.

Добавим еще один документ в нашу коллекцию:

 $ cat << EOF | curl -d @- -H'X-Access-Token:myaccess01' -X POST http://localhost:9191/family
 {
 "firstName":"Jack",
 "lastName":"Parker",
 "age":35,
 "pets":[{"name":"Sonic", "kind":"mouse", "likes":[]}]
 }
 EOF

Теперь запрашивайте только владельцев pet firstName и lastName из коллекции.

 > k query family /* | /{firstName,lastName}
 < k     3       {"firstName":"Jack","lastName":"Parker"}
 < k     1       {"firstName":"John","lastName":"Doe"}
 < k

Добавить массив pets для каждого документа

> k query family /* | /{firstName,lastName} + /pets
 < k     3       {"firstName":"Jack","lastName":"Parker","pets":[...
 < k     1       {"firstName":"John","lastName":"Doe","pets":[...


Исключение только документы pets из документов

> k query family /* | all - /pets
 < k     3       {"firstName":"Jack","lastName":"Parker","age":35}
 < k     1       {"firstName":"John","lastName":"Doe","age":28,"address":{"city":"New York","street":"Fifth Avenue"}}
 < k

Здесь используются все ключевые слова, обозначающие весь документ.

Получение age и первого pet в массиве pets.

> k query family /[age > 20] | /age + /pets/0
 < k     3       {"age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
 < k     1       {"age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]}]}
 < k

Присоединения коллекции JQL

Join реализует ссылку на документ к реальному объекту документа, который заменит ссылку на месте.

Документы объединяются только по их первичным ключам.

Ссылочные ключи должны храниться в документе реферера в виде числового или строкового поля.

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

>/.../field<collection

Где:

  • field - поле JSON содержащее первичный ключ присоединяемого документа.
  • <- Специальный символ метки, который инструктирует движку EJDB замену ключа поля телом присоединенного документа.
  • collection - имя коллекции БД, в которой находятся объединенные документы.

Документ-реферер не будет затронут, если соответствующий документ не найден.

Вот простая демонстрация объединений коллекций в нашей интерактивной оболочке websocket:


 > k add artists {"name":"Leonardo Da Vinci", "years":[1452,1519]}
 < k     1
 > k add paintings {"name":"Mona Lisa", "year":1490, "origin":"Italy", "artist": 1}
 < k     1
 > k add paintings {"name":"Madonna Litta - Madonna And The Child", "year":1490, "origin":"Italy", "artist": 1}
 < k     2
 # Lists paintings documents
 > k @paintings/*
 < k     2       {"name":"Madonna Litta - Madonna And The Child","year":1490,"origin":"Italy","artist":1}
 < k     1       {"name":"Mona Lisa","year":1490,"origin":"Italy","artist":1}
 < k
 >
 # Do simple join with artists collection
 > k @paintings/* | /artist<artists
 < k     2       {"name":"Madonna Litta - Madonna And The Child","year":1490,"origin":"Italy",
                  "artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
 < k     1       {"name":"Mona Lisa","year":1490,"origin":"Italy",
                  "artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
 < k
  # Strip all document fields except `name` and `artist` join
 > k @paintings/* | /artist<artists + /name + /artist/*
 < k     2       {"name":"Madonna Litta - Madonna And The Child","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
 < k     1       {"name":"Mona Lisa","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
 < k
 >
 # Same results as above:
 > k @paintings/* | /{name, artist<artists} + /artist/*
 < k     2       {"name":"Madonna Litta - Madonna And The Child","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
 <  k     1       {"name":"Mona Lisa","artist":{"name":"Leonardo Da Vinci","years":[1452,1519]}}
 < k

Порядок результатов JQL

 ORDERBY = ({ 'asc' | 'desc' } PLACEHOLDER | json_path)...

Добавим еще один документ, затем отсортируем документы в коллекции по возрастанию firstName и по убыванию возраста.

> k add family {"firstName":"John", "lastName":"Ryan", "age":39}
 < k     4
 > k query family /* | /{firstName,lastName,age} | asc /firstName desc /age
 < k     3       {"firstName":"Jack","lastName":"Parker","age":35}
 < k     4       {"firstName":"John","lastName":"Ryan","age":39}
 < k     1       {"firstName":"John","lastName":"Doe","age":28}
 < k

asc, desc инструкции могут использовать индексы, определенные для сбора, чтобы избежать отдельной стадии сортировки документов.

Параметры JQL

OPTS = { 'skip' n | 'limit' n | 'count' | 'noidx' | 'inverse' | ORDERBY }...
  • skip n пропустить первые n записей перед первым элементом в наборе результатов
  • limit n установить максимальное количество документов в наборе результатов
  • count возвращает только количество найденных документов

 > k query family /* | count
 < k     3
 < k

  • noidx не используйте индексы для выполнения запроса.
  • inverse по умолчанию сканирует документы от самых последних добавленных к более старым.. Эта опция инвертирует направление сканирования в противоположное и активирует режим noidx. Не имеет никакого эффекта, если запрос имеет условия сортировки asc / desc.

Индексы JQL и советы по производительности

Индекс базы данных можно построить для любого пути к полю JSON, содержащего значения числа или типа строки. Индекс может быть уникальным - не допускающим дублирования значений и non unique. Используются следующие флаги битовой маски индексного режима (определенные в ejdb2.h):

Индексный режим Описание
0x01 EJDB_IDX_UNIQUE Уникальный индекс
0x04 EJDB_IDX_STR Индекс для JSON string типа значения поля
0x08 EJDB_IDX_I64 Индекс для 8 bytes width целочисленного значения полей со знаком
0x10 EJDB_IDX_F64 Индекс для 8 bytes width значения полей с плавающей запятой со знаком

Например, уникальный индекс строкового типа будет указан EJDB_IDX_UNIQUE | EJDB_IDX_STR = 0x05. Индекс может быть определен только для одного типа значения, расположенного по определенному пути в документе json.

Давайте определим неуникальный строковый индекс для пути / lastName:


 > k idx family 4 /lastName
 < k

Выбор индекса для запросов на основе набора эвристических правил.

Вы всегда можете проверить использование индекса, введя команду объяснения в WS API:

 > k explain family /[lastName=Doe] and /[age!=27]
 < k     explain [INDEX] MATCHED  STR|3 /lastName EXPR1: 'lastName = Doe' INIT: IWKV_CURSOR_EQ
 [INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = Doe' INIT: IWKV_CURSOR_EQ
  [COLLECTOR] PLAIN

При использовании индексов EJDB2 учитываются следующие операторы:

  • Только один индекс может быть использован для конкретного выполнения запроса
  • Если запрос or состоит из присоединенной части на верхнем уровне или содержит отрицательные выражения на верхнем уровне выражения запроса-индексы вообще не будут использоваться. Так что никаких индексов ниже:

 /[lastName != Andy]

 /[lastName = "John"] or /[lastName = Peter]

Но будет использоваться индекс / lastName, определенный выше


 /[lastName = Doe]

 /[lastName = Doe] and /[age = 28]

 /[lastName = Doe] and not /[age = 28]

 /[lastName = Doe] and /[age != 28]


  • Следующие операторы поддерживаются индексами (ejdb 2.0.x):

eq, =

gt, >

gte, >=

lt, <

lte, <=

in

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

 > k add books {"name":"Mastering Ultra", "tags":["ultra", "language", "bestseller"]}
 < k     1
 > k add books {"name":"Learn something in 24 hours", "tags":["bestseller"]}
 < k     2
 > k query books /*
 < k     2       {"name":"Learn something in 24 hours","tags":["bestseller"]}
 < k     1       {"name":"Mastering Ultra","tags":["ultra","language","bestseller"]}
 < k

Создать индекс строки для /tags


 > k idx books 4 /tags
 < k

Фильтрация книг по тегу bestseller и демонстрация использованного индекса в запросе:

> k explain books /tags/[** in ["bestseller"]]
 < k     explain [INDEX] MATCHED  STR|4 /tags EXPR1: '** in ["bestseller"]' INIT: IWKV_CURSOR_EQ
 [INDEX] SELECTED STR|4 /tags EXPR1: '** in ["bestseller"]' INIT: IWKV_CURSOR_EQ
 [COLLECTOR] PLAIN

 < k     1       {"name":"Mastering Ultra","tags":["ultra","language","bestseller"]}
 < k     2       {"name":"Learn something in 24 hours","tags":["bestseller"]}
 < k

Совет по производительности: физический порядок документов

Все документы в коллекции отсортированы по первичному ключу в порядке descending. Поэтому, если вы используете автоматически сгенерированные ключи (ejdb_put_new), вы можете быть уверены, что документы, полученные в результате запроса полной проверки, будут упорядочены по времени вставки в порядке убывания, если только вы не используете сортировку запросов, индексы или ключевое слово inverse.

Совет по производительности: грубое сканирование против индексированного доступа

Во многих случаях использование индекса может снизить общую производительность запросов. Поскольку коллекция индексов содержит только ссылки на документы (id), и механизм может выполнить дополнительную выборку документов по первичному ключу для завершения сопоставления запроса. Так что для не очень больших коллекций грубое сканирование может работать лучше, чем сканирование с использованием индексов. Точные операции сопоставления: eq, in и sorting по порядку выиграет естественный индекс в большинстве случаях.

Совет по производительности: избавление от ненужных данных документа

Если вы хотите обновить набор документов с apply или del операциями, но не хотите получать их все в результате запроса - просто добавьте count модификатор запроса, чтобы избавиться от ненужной передачи данных и преобразования данных JSON.

HTTP REST / конечная точка API Websocket

Механизм EJDB обеспечивает возможность запуска отдельного работника конечной точки HTTP / Websocket, предоставляя сетевой API для запросов и модификаций данных.

Самый простой способ выставить базу данных по сети - использовать автономный сервер JBS. (Конечно, если вы планируете избегать интеграции C API).

JBS-сервер


 jbs -h

 EJDB 2.0.0 standalone REST/Websocket server. http://ejdb.org

  --file <>	Database file path. Default: db.jb
  -f <>    	(same as --file)
  --port ##	HTTP port number listen to. Default: 9191
  -p ##    	(same as --port)
  --bind <>	Address server listen. Default: localhost
  -b <>    	(same as --bind)
  --access <>	Server access token matched to 'X-Access-Token' HTTP header value
  -a <>      	(same as --access)
  --trunc   	Cleanup existing database file on open
  -t        	(same as --trunc)
  --wal   	Use write ahead logging (WAL). Must be set for data durability.
  -w      	(same as --wal)

  Advanced options
  --sbz ##	Max sorting buffer size. If exceeded, an overflow temp file for data will be created. Default: 16777216, min: 1048576
  --dsz ##	Initial size of buffer to process/store document on queries. Preferable average size of document. Default: 65536, min: 16384
  --bsz ##	Max HTTP/WS API document body size. Default: 67108864, min: 524288

 Use any of the following input formats:
  -arg <value>	-arg=<value>	-arg<value>
 Use the -h, -help or -? to get this information again.

HTTP API

Доступ к конечной точке HTTP может быть защищен токеном, указанным с помощью флага команды --access, или параметрами C API EJDB_HTTP. Если токен доступа указан на сервере, клиент должен предоставить значение HTTP-заголовка X-Access-Token. Если токен требуется и не предоставлен клиентом, сообщается код HTTP 401. Если токен доступа не соответствует токену при условии, что будет возвращен код HTTP 403. За любые другие ошибки сервер ответит 500 кодом ошибки.

REST API

POST /{collection}

Добавляет новый документ в collection если:

  • 200 success. Body: новый идентификатор документа как номер int64

PUT /{collection}/{id}

Заменяет / сохраняет документ под определенным числовым id если:

  • 200 on success.  Пустое тело

DELETE /{collection}/{id}

Удаляет документ, идентифицированный по идентификатору, из collection если:

  • 200 on success.  Пустое тело
  • 404 если документ не найден

PATCH /{collection}/{id}

Патч-документ, идентифицируется по id rfc7396[Источник 23] , rfc6902[Источник 24] данным если:

  • 200 on success.  Пустое тело

GET | HEAD /{collections}/{id}

Загрузка документа идентифицированного по id из коллекции:

  • 200 on success. Тело: Текст документа JSON.
content-type:application/json
content-length:
  • 404 если документ не найден

POST /

Вызвать коллекцию по предоставленному запросу как тело POST, можно в том случае если тело запроса содержит имя коллекции, используемое в первом элементе фильтра:

@collection_name/...

Заголовок запроса:

  • X-Hints разделенная запятыми дополнительная рекомендация для движка базы данных ejdb2.
  • explain Показывает план выполнения запроса перед первым элементом в наборе результатов, разделенных строкой.

Ответ:

  • Данные ответа, переданные с использованием частичной кодировки HTTP[Источник 25]
  • 200 on success.
  • Документы JSON, разделенные \ n в следующем формате:

\r\n<document id>\t<document JSON body>
...

Пример:


curl -v --data-raw '@family/[age > 18]' -H 'X-Access-Token:myaccess01' http://localhost:9191
* Rebuilt URL to: http://localhost:9191/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9191 (#0)
> POST / HTTP/1.1
> Host: localhost:9191
> User-Agent: curl/7.58.0
> Accept: */*
> X-Access-Token:myaccess01
> Content-Length: 18
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 200 OK
< connection:keep-alive
< content-type:application/json
< transfer-encoding:chunked
<

4	{"firstName":"John","lastName":"Ryan","age":39}
3	{"firstName":"Jack","lastName":"Parker","age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
1	{"firstName":"John","lastName":"Doe","age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]},{"name":"Grenny","kind":"parrot","likes":["green color","night","toys"]}],"address":{"city":"New York","street":"Fifth Avenue"}}
* Connection #0 to host localhost left intact


url --data-raw '@family/[lastName = "Ryan"]' -H 'X-Access-Token:myaccess01' -H 'X-Hints:explain' http://localhost:9191
[INDEX] MATCHED  STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
[INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
 [COLLECTOR] PLAIN
--------------------
4	{"firstName":"John","lastName":"Ryan","age":39}

OPTIONS /

Получение метаданных JSON ejdb и доступных методов HTTP в заголовке ответа Allow. Пример:

curl -X OPTIONS -H 'X-Access-Token:myaccess01'  http://localhost:9191/
{
 "version": "2.0.0",
 "file": "db.jb",
 "size": 16384,
 "collections": [
  {
   "name": "family",
   "dbid": 3,
   "rnum": 3,
   "indexes": [
    {
     "ptr": "/lastName",
     "mode": 4,
     "idbf": 64,
     "dbid": 4,
     "rnum": 3
    }
   ]
  }
 ]
}

Websocket API

EJDB поддерживает простой текстовый протокол по протоколу HTTP websocket. Вы можете использовать интерактивный инструмент командной строки websocket wscat для связи с сервером вручную.

Команды

Команда: ?

Ответ на команду будет получен в виде следующего текстового сообщения:


wscat  -H 'X-Access-Token:myaccess01' -q -c http://localhost:9191
> ?
<
<key> info
<key> get     <collection> <id>
<key> set     <collection> <id> <document json>
<key> add     <collection> <document json>
<key> del     <collection> <id>
<key> patch   <collection> <id> <patch json>
<key> idx     <collection> <mode> <path>
<key> rmi     <collection> <mode> <path>
<key> rmc     <collection>
<key> query   <collection> <query>
<key> explain <collection> <query>
<key> <query>
>

Примечание о префиксе <key> перед каждой командой: это произвольный ключ, выбранный клиентом и предназначенный для идентификации конкретного запроса веб-сокета. Этот ключ будет возвращен в ответ на запрос и позволяет клиенту идентифицировать этот ответ для своего конкретного запроса.

Ошибки возвращаются в следующем формате:

<key> ERROR: <error description>

Команда: <key> info

Получение метаданных базы данных в виде документа JSON.

Команда: <key> get <collection> <id>

Получение документа, идентифицированного по id из collection. Если документ не был найден, IWKV_ERROR_NOTFOUND то он будет возвращен.

Пример:


> k get family 3
< k     3       {
 "firstName": "Jack",
 "lastName": "Parker",
 "age": 35,
 "pets": [
  {
   "name": "Sonic",
   "kind": "mouse",
   "likes": []
  }
 ]
}

Если документ не найден, мы получим ошибку:


> k get family 55
< k ERROR: Key not found. (IWKV_ERROR_NOTFOUND)
>

Команда: <key> del <collection> <id>

Удаление документа, идентифицированный по id из collection. Если документ не был найден, IWKV_ERROR_NOTFOUND то он будет возвращен.

Команда:<key> patch <collection> <id> <patch json>

Примените патч rfc7396 или rfc6902 к документу, идентифицированному по id. Если документ не был найден, IWKV_ERROR_NOTFOUND то он будет возвращен.

Команда:<key> query <collection> <query>

Выполнение запроса по документам в указанной collection. Ответ: Набор сообщений WS с телами документов, оканчивающимися последним сообщением с пустым телом.


> k query family /* | /firstName
< k     4       {"firstName":"John"}
< k     3       {"firstName":"Jack"}
< k     1       {"firstName":"John"}
< k

Примечание о последнем сообщении: <key> без тела.

Команда:<key> explain <collection> <query>

То же самое, что <key> query <collection> <query>, но первое ответное сообщение будет иметь префикс <key> explain и содержит план выполнения запроса. Пример:


> k explain family /* | /firstName
< k     explain [INDEX] NO [COLLECTOR] PLAIN

< k     4       {"firstName":"John"}
< k     3       {"firstName":"Jack"}
< k     1       {"firstName":"John"}
< k

Выполнение текста запроса: тело запроса должно содержать имя коллекции, используемое в первом элементе фильтра: @collection_name/.... Последовательность действие такое же, как и для <key> query <collection> <query>

Команда:<key> idx <collection> <mode> <path>

Сопоставьте индекс с указанным mode (битовой маской) для заданного пути и коллекции json. Коллекция будет создана, если её не существует.

Индексный режим Описание
0x01 EJDB_IDX_UNIQUE Уникальный индекс
0x04 EJDB_IDX_STR Индекс для типа значения string поля JSON
0x08 EJDB_IDX_I64 Индекс для значений целых полей 8 bytes width
0x10 EJDB_IDX_F64 Индекс для значений ширины поля 8 bytes width

Пример Установка уникального строкового индекса (0x01 & 0x04) = 5 в поле /name JSON:


k idx mycollection 5 /name

Команда:<key> rmi <collection> <mode> <path>

Удаление индекса с указанным mode (битовой маской) для заданного пути и коллекции json. Вывести ошибку, если данный индекс не найден.

Команда:<key> rmc <collection>

Удаление коллекции и всех ее данные. Примечание. Если коллекция не найдена, об ошибках не сообщается.

Поддержка Docker

Если у вас установлен Docker, вы можете создать образ Docker и запустить его в контейнере


cd docker
docker build -t ejdb2 .
docker run -d -p 9191:9191 --name myEJDB ejdb2 --access myAccessKey

или получите образ ejdb2 прямо из Docker Hub

docker run -d -p 9191:9191 --name myEJDB softmotions/ejdb2 --access myAccessKey

C API

EJDB может быть встроен в любое приложение C / C ++. C API документирован в следующих заголовках:

  • ejdb.h основные функции API
  • jbl.h API управления документами JSON
  • jql.h API построение запросов

Пример приложения:

#include <ejdb2/ejdb2.h>

#define CHECK(rc_)          \
  if (rc_) {                 \
    iwlog_ecode_error3(rc_); \
    return 1;                \
  }

static iwrc documents_visitor(EJDB_EXEC *ctx, const EJDB_DOC doc, int64_t *step) {
  // Print document to stderr
  return jbl_as_json(doc->raw, jbl_fstream_json_printer, stderr, JBL_PRINT_PRETTY);
}

int main() {

  EJDB_OPTS opts = {
    .kv = {
      .path = "example.db",
      .oflags = IWKV_TRUNC
    }
  };
  EJDB db;     // EJDB2 storage handle
  int64_t id;  // Document id placeholder
  JQL q = 0;   // Query instance
  JBL jbl = 0; // Json document

  iwrc rc = ejdb_init();
  CHECK(rc);

  rc = ejdb_open(&opts, &db);
  CHECK(rc);

  // First record
  rc = jbl_from_json(&jbl, "{\"name\":\"Bianca\", \"age\":4}");
  RCGO(rc, finish);
  rc = ejdb_put_new(db, "parrots", jbl, &id);
  RCGO(rc, finish);
  jbl_destroy(&jbl);

  // Second record
  rc = jbl_from_json(&jbl, "{\"name\":\"Darko\", \"age\":8}");
  RCGO(rc, finish);
  rc = ejdb_put_new(db, "parrots", jbl, &id);
  RCGO(rc, finish);
  jbl_destroy(&jbl);

  // Now execute a query
  rc =  jql_create(&q, "parrots", "/[age > :age]");
  RCGO(rc, finish);

  EJDB_EXEC ux = {
    .db = db,
    .q = q,
    .visitor = documents_visitor
  };

  // Set query placeholder value.
  // Actual query will be /[age > 3]
  rc = jql_set_i64(q, "age", 0, 3);
  RCGO(rc, finish);

  // Now execute the query
  rc = ejdb_exec(&ux);

finish:
  jql_destroy(&q);
  jbl_destroy(&jbl);
  ejdb_close(&db);
  CHECK(rc);
  return 0;
}

Скомпилируйте и запустите:


gcc -std=gnu11 -Wall -pedantic -c -o example1.o example1.c
gcc -o example1 example1.o -lejdb2

./example1
{
 "name": "Darko",
 "age": 8
}{
 "name": "Bianca",
 "age": 4
}

Лицензия

MIT License

Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Применение

Существует определенный класс приложений, где удобно использовать встраиваемые СУБД, это: легковесные приложения, использующие СУБД для доступа к данным, хранимых на сменных носителях (DVD и проч.) и которые сами хранятся на этих носителях; компьютерные игры, хранящие данные игрового процесса и самой игры; большой класс приложений, предназначенных для работы на мобильных устройствах. Достаточно часто требуется соблюдение конфиденциальности хранимых данных от неавторизованного доступа, в частности, это очень актуально для приложений игровой индустрии и мобильных приложений, хранящих персональные данные пользователя. В данном контексте рассматривается задача эффективной реализации шифрования данных во встраиваемой СУБД EJDB. [Источник 26]

Источники

  1. встроенный JSON Database Engine // EJDB — Embedded JSON Database engine. URL: https://www.findbestopensource.com/product/ejdb (дата обращения: 12.06.2020).
  2. Новосибирский Государственный Университет // НГУ. URL:https://www.nsu.ru/n/
  3. The Story of the IT-depression, birds and EJDB 2.0. URL: https://medium.com/@adamansky/ejdb2-41670e80897c (дата обращения: 16.06.2020).
  4. Softmotions/ejdb // Github. Дата обновления: 16.05.2020. URL: https://github.com/Softmotions/ejdb (дата обращения: 13.06.2020).
  5. C11 key/value database engine. URL: https://iowow.io/(дата обращения: 13.06.2020).
  6. РЕАЛИЗАЦИЯ ШИФРОВАНИЯ ДАННЫХ ВО ВСТРАИВАЕМОЙ СУБД EJDB // Архитектура EJDB. Дата обновления: 08.11.2018: URL: https://nsu.ru/xmlui/bitstream/handle/nsu/3805/2014_V12_No2_6.pdf (дата обращения: 15.06.2020).
  7. C11 key/value database engine // Features. URL: https://iowow.io (дата обращения: 23.06.2020).
  8. Обзор библиотеки хранения JSON данных EJDB. обновления: 22.11.2012. URL: https://habr.com/ru/sandbox/52301/ (дата обращения: 22.06.2020).
  9. Обзор библиотеки хранения JSON данных EJDB // Что было использовано из tokyocabinet. Дата обновления: 22.11.2012. URL: https://habr.com/ru/sandbox/52301/ (дата обращения: 22.06.2020).
  10. Softmotions /ejdb // README.md Дата обновления: 20.06.2020.. URL: https://github.com/Softmotions/ejdb (дата обращения: 18.06.2020).
  11. Port of facil.io for Windows #257. Дата обновления: 18.07.2019. URL: https://github.com/Softmotions/ejdb/issues/257 (дата обращения: 14.06.2020).
  12. EJDB2 Node.js native binding. Дата обновления: 20.05.2020. URL: https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_node#how-build-it-manually (дата обращения: 14.06.2020).
  13. React Native iOS binding #273. Дата обновления: 13.01.2020. URL: https://github.com/Softmotions/ejdb/issues/273 (дата обращения: 14.06.2020).
  14. Windows cross compilation. Дата обновления: 19.07.2019. URL: https://github.com/Softmotions/ejdb/blob/master/WINDOWS.md (дата обращения: 14.06.2020).
  15. EJDB2Swift. Дата обновления: 19.07.2019. URL: https://github.com/Softmotions/EJDB2Swift (дата обращения: 18.06.2020).
  16. Windows cross compilation. Дата обновления: 19.07.2019. URL: https://github.com/Softmotions/ejdb/blob/master/WINDOWS.md (дата обращения: 18.06.2020).
  17. EEJDB2 Flutter integration. Дата обновления: 16.05.2020. URL: https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter(дата обращения: 18.06.2020).
  18. EJDB2 React Native binding. Дата обновления: 16.05.2020. URL: https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_react_native(дата обращения: 18.06.2020).
  19. пример тестов. Дата обновления: 14.05.2020. URL: https://github.com/Softmotions/ejdb/blob/master/src/jql/tests/jql_test1.c(дата обращения: 18.06.2020).
  20. HTTP REST/Websocket API endpoint. Дата обновления: 26.02.2020. URL: https://github.com/Softmotions/ejdb/blob/master/src/jbr/README.md(дата обращения: 18.06.2020).
  21. wscat. URL: https://www.npmjs.com/package/@softmotions/wscat(дата обращения: 18.06.2020).
  22. jbs server. Дата обновления: 26.02.2020. URL: https://github.com/Softmotions/ejdb/blob/master/src/jbr/README.md(дата обращения: 18.06.2020).
  23. JSON Merge Patch. Дата обновления: 01.10.2014. URL: https://tools.ietf.org/html/rfc7396(дата обращения: 22.06.2020).
  24. JavaScript Object Notation (JSON) Patch. Дата обновления: 01.04.2013. URL: https://tools.ietf.org/html/rfc6902(дата обращения: 22.06.2020).
  25. Chunked transfer encoding.URL: https://en.wikipedia.org/wiki/Chunked_transfer_encoding(дата обращения: 22.06.2020).
  26. Сравнение стандарта шифрования РФ и нового стандарта шифрования США.. URL: http://www.enlight.ru/crypto/articles/vinokurov/gosaes_i.htm (дата обращения: 17.06.2020).