[JavaScript, NoSQL, Node.JS] Инструменты Node.js разработчика. Какие ODM нам нужны
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
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
===========
Похожие новости:
- [CSS, JavaScript, Интерфейсы, HTML] Динамическое меню c поддержкой touch move и mouse move на RevolveR
- [Разработка веб-сайтов, JavaScript, ReactJS] Как эффективно применять React Context (перевод)
- [JavaScript, ReactJS, Визуализация данных, Инфографика, Разработка веб-сайтов] Визуализация сложных данных с использованием D3 и React
- [JavaScript] Удобная платформа для подбора библиотек и фреймворков JavaScript — openbase (перевод)
- [Разработка веб-сайтов, JavaScript, VueJS] Отдаем корректный код 404 в связке VUE SPA + SSR
- Доступен пакетный менеджер NPM 7.0
- [Node.JS, IT-компании] Мир на ладони или как мы с помощью чат-бота оптимизируем рабочие процессы сотрудников
- [MongoDB] MongoDB — базовые возможности
- [Ненормальное программирование, JavaScript, Графический дизайн] QR-художество
- [Разработка веб-сайтов, CSS, JavaScript, Canvas, ReactJS] 24 октября приглашаем на онлайн-митап Hot Frontend в Казани
Теги для поиска: #_javascript, #_nosql, #_node.js, #_odm, #_mongodb, #_arangodb, #_couchdb, #_orientdb, #_nodejs, #_javascript, #_javascript, #_nosql, #_node.js
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 22:23
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
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 } 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); } } } 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 } =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 22:23
Часовой пояс: UTC + 5