[JavaScript, NoSQL, Node.JS] Инструменты Node.js разработчика. Какие ODM нам нужны

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
19-Окт-2020 00:31

ODM - Object Document Mapper - используется преимущественно для доступа к документоориенриирвоанным базам данных, к которым относятся MongoDB, CouchDB, ArangoDB, OrientDB (последние две базы данных гибридные) и некоторые другие.Прежде чем перейти к рассмотрению вопроса, озвученного в названии сообщения, приведу статистику скачивания пакетов из публичного регистра npm.ТаблицаСтатистика скачивания пакетов для работы с реляционными и документоориентированными базами данных из публичного регистра npmПакет (npm)Количество скачиваний в неделюБаза данныхpg1 660 369PostgreSQLmysql713 548MySQLmongodb (из них 1 034 051 вместе с mongoose)1 974 992MongoDBmongoose1 034 051MongoDBnano60 793CouchDBPouchDB25 707CouchDBarangojs7 625ArangoDBorientjs598OrientDBИз таблицы можно сделать очень интересные выводы:1) Использование MongoDB в проектах на nodejs почти сравнялось с использованием реляционных баз данных, и превысило использование одной отдельно взятой реляционной базы данных PostgreSQL или MySQL;2) В половине проектов для доступа к MongoDB используется библиотека mongoose (ODM);3) В половине проектов для доступа к MongoDB не используется библиотека mongoose. А это означает, что не используется сторонняя ODM, так как другой популярной библиотеки ODM для MongoDB нет.4) Такие базы данных как ArangoDB, OrtintDB существенно менее популярны, чем MongoDB, и даже CoucbDB, и не имеют общепризнанных ODM.Сначала остановлюсь на мотивации использования документоориентированных баз данных в проектах на Node.js. Отставим в сторону маркетинговую составляющую, хотя ее доля возможно более 50% из общего количества в приведенной статистике. Будем исходить что это все же кому-то действительно нужно, по-настоящему.Модель данных в документоориентирвоанных базах данных близка к привычной многим в реляционных базах данных. Только вместо таблицы - коллекция, вместо строки таблицы - документ. Дает ли применение коллекции документов вместо таблицы преимущества и какие? Рассмотрим возможные варианты аргументации.1) Отсутствие жесткой схемы. Сейчас это уже не аргумент. Так как MySQL и PostgrSQL обзавелись типом данных json, который может то же самое и даже больше (например остается возможность запросов с JOIN). Но даже не это главное. Как показывает статистика, половина проектов на MongoDB использует mongoose, в которой задается жесткая схема документа в коллекции.2) Встроенные документы. Сейчас тоже не аргумент. MySQL и PostgrSQL имеют тип данных json, которые может то же самое. Надо отдать должное, что внедрение этого типа данных было ускорено развитием NoSQL.3) Репликация и шардирование. Да, да и еще раз да. Вот то, что может быть аргументом "за" использование документоориентированных баз данных в проекте.От чего придется отказаться, отказавшись от использования реляционных баз данных: как известно, ACID и JOIN. (Хотя тут есть варианты)Итак, с мотивацией определились. Теперь я хотел бы сказать, что именно репликация и шардирование, по моему мнению, в MongoDB как раз не самый лучший из вариантов среди NoSQL. Поэтому я всегда смотрел и на других лидеров.Первой, конечно, была CouchDB. Как говорил ее создатель, что эта база данных все делает плохо, за исключением репликации. И действительно, репликация в CouchDB реализована просто и ясно. В базе данных сохраняются все версии документов. Все они распространяются между репликами в произвольном направлении. Если два клиента изменили один и тот же документ на разных репликах, то оба получат успешный ответ о выполнении операции, однако в процессе репликации произойдет конфликт, который нужно будет разрешать явно в пользу одной из версий.CouchDB, также как и реляционные базы данных, испытала влияние MongoDB, и в одной из новых версий получила более удобный язык запросов mango, который похож на язык запросов MongoDB.Но все же CouchDB существенно проигрывает по скорости другим документоориентированным базам данных, что не говорит в пользу ее выбора для достижения высокой производительности, собственно для чего и используется репликация и шардрирвоание.Поэтому следующим кандидатом я всегда рассматривал ArangoDB. Эта база данных поддерживает работу с документами и графами. До версии 3.4 ArangoDB имела проблемы при работе с большими коллекциями (которые превышают объем оперативной памяти) - вплоть до полного зависания сервера. Проблема эта фигурировала в issue, и даже отрицалась разработчиками, но была пофикшена в версии 3.4, что открыло возможности для ее использования.В плане репликации и шардирования ArangoDB напоминает CouchDB. И даже гарантирует ACID в Еnterprise версии продукта.JOIN в ArangoDB также не является проблемой. Вот так будет выглядеть классический запрос MANY-TO-MANY:
FOR a IN author
      FOR ba IN bookauthor
      FILTER a._id == ba.author
        FOR b IN book
        FILTER b._id == ba.book
        SORT a.name, b.title
    RETURN { author: a, book: b }
Это не выполняемый код на JavaScript с полным перебором всех записей (как может показаться на первый взгляд). Это такой очень оригинальный язык запросов, с синтаксисом JavaScript который является аналогом SQL и называется AQL. Подробности можно узнать в статье на Хабре.ArangoDB также позволяет публиковать REST сервисы прямо в базе данных (Foxx) и делать поисковые запросы, включая нечеткий поиск (fuzzy search), что позволяет строить поиск без Elasticsearch (Elasticsearch конечно более мощный инструмент, но проблему составляет синхронизация данных в основной базе данных и в Elasticsearch).Однако, на сегодняшний день нет ODM, которая позволила бы удобно и надежно работать с ArangoDB, и это существенный сдерживающий фактор в её использовании в реальном проекте. Поэтому я неоднократно приступал к поиску решения для ODM. В конце концов решение начало приобретать явные очертания и я его представляю в этом сообщении.Самое существенное, что есть в решении - это понимание того функционала, который должна решать ODM. В этом смысле я хочу сослаться на проект universal-router (см. сообщение на Хабре), который из всего многообразия функций, к которым мы уже успели привыкнуть в роутерах React.js или Vue.js, выделили главный функционал на котором построили свое решение.Если говорить об ODM, таким функционалом, без которого не обойтись, является по моему мнению ровно три функции:
1) Преобразование JSON (полученного из базы данных) в типизированную модель или коллекцию;2) Преобразование типизированной модели или коллекции в JSON для сохранения в базе данных;3) Преобразование типизированной модели или коллекции в JSON для отправки клиенту.И совершенно исключается из ODM любая автогенерация запросов в базу данных, которую можно выполнить и средствами драйверов, имеющих достаточно удобный API.При этом есть смысл максимально использовать возможности Typescript (например декораторы, рефлексию, метаданные).
export class Reposytory {
  private db: Database;
  constructor() {
    this.db = db;
  }
  @collection(Author)
  async authorFindAll() {
    const row = await this.db.query({
      query: 'for row in authors return row',
      bindVars: {},
    });
    return row.all();
  }
  @model(Author)
  async authorCreate(author: Author): Promise<Author> {
    const doc = await this.db.query({
      query: 'insert @author into authors let doc = NEW return doc',
      bindVars: { 'author': author }
    });
    return doc.next();
  }
}
Код декораторов будет довольно лаконичен:
export function collection(Constructor: new(...args: any[]) => void) {
  return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor): void => {
      const originalValue = descriptor.value;
      descriptor.value = async function(...args: any[]) {
        const plainData = await originalValue.apply(this, args)
        const data = new Array();
        plainData.forEach((item: any) => data.push(new Constructor(item)));
        return data;
      }
    }
}
export function model(Constructor: new(...args: any[]) => void) {
  return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor): void => {
      const originalValue = descriptor.value;
      descriptor.value = async function(...args: any[]) {
        const plainData = await originalValue.apply(this, args)
        return new Constructor(plainData);
      }
    }
}
Что касается модели документа, я построил схему модели на таких декораторах:attr(Type?) - атрибут - то есть то что сохраняется в базе данных и не является вычислимым параметром;optional(Type?) - не обязательное значение;array(Type?) - типизированная коллекция;translatable(Type?) - значение, сохраняющееся в базе данных виде объекта и возвращающееся клиенту в виде строки с выбранной локалью;group(...args: string[]) - список групп клиентов, которым доступно значение.На таких декораторах можно построить описание объекта:
import {Model, ModelType} from '../src';
import {optional, attr, array, getter, group, _type, translatable} from '../src';
import {Translatable, TranslatableType} from '../src';
interface AddressType extends ModelType {
    city: string,
    street: Translatable,
    house: string,
    appartment?: number,
}
interface AuthorType extends ModelType{
    name: Translatable,
    address: AddressType,
}
export class Address extends Model<AddressType> implements AddressType {
    @attr()
    @group('admin', 'user')
    @translatable(Translatable)
    public city!: string;
    @attr()
    @group('admin')
    @translatable(Translatable)
    public street!: Translatable;
    @attr()
    @group('admin')
    public house!: string;
    @attr()
    @optional()
    @group('admin')
    public appartment?: number;
}
export class Author extends Model<AuthorType> implements AuthorType  {
    @attr(Translatable)
    @translatable(Translatable)
    @group('admin', 'user')
    public name!: string;
    @attr(Address)
    @group('admin', 'user')
    public address!: Address
}
Результаты исследования представлены в репозитарии.Желающих обсудить приглашаю в чат https://t.me/arangodb_odm
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_javascript, #_nosql, #_node.js, #_odm, #_mongodb, #_arangodb, #_couchdb, #_orientdb, #_nodejs, #_javascript, #_javascript, #_nosql, #_node.js
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 16:06
Часовой пояс: UTC + 5