MongoDB – одна из самых популярных документ-ориентированных баз данных класса NoSQL с большим сообществом пользователей. Ее основными преимуществами являются гибкость схемы хранения, иерархическая структура документов, поддержка расширенного набора типов данных. Сегодня MongoDB чаще всего используется как бэкенд веб- и мобильных приложений.

Казалось бы, зачем может потребоваться извлекать схему данных в schemaless database? Однако это может быть крайне полезно и в некоторых ситуациях абсолютно необходимо:

  • Репликация данных в аналитическое хранилище

  • Интерактивная аналитика из BI-инструментов (SQL)

  • Аудит имеющейся структуры БД

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

Причины для получения схемы всех коллекций

Репликация данных в аналитическое хранилище

Экспорт из MongoDB в реляционные аналитические СУБД сопряжен с рядом сложностей:

  • Отсутствие единой заранее заданной схемы документов

  • Наличие вложенных документов и массивов динамической структуры

  • Разные документы одной коллекции могут иметь несопоставимые типы данных

  • В документ (запись) могут быть добавлены новые атрибуты в любой момент времени

  • Различные допустимые значения длины текстовых атрибутов (необходимость в column resize)

Документ-ориентированное хранение предполагает гибкую схему
Документ-ориентированное хранение предполагает гибкую схему

Интерактивная аналитика из BI-инструментов

Современные BI-решения выполняют роль визуального конструктора и генератора запросов, прежде всего на языке SQL. И, в подавляющем большинстве случаев, работают они с двумерными табличными структурами данных.

Однако MongoDB не поддерживает SQL в чистом виде, но свой диалект языка работы с данными – MongoDB Query Language (MQL). Таким образом, для поддержки работы из популярных BI-решений, таких как Metabase, Tableau, Power BI необходим медиаторный слой в виде транслятора запросов на SQL в запросы на языке MQL.

BI Connector выполняет роль транслятора запросов и данных между BI-инструментами и MongoDB
BI Connector выполняет роль транслятора запросов и данных между BI-инструментами и MongoDB

Этот слой должен обладать достаточной информацией для формирования плана запросов, в том числе для выполнения операций:

  • Проекция (projection)

  • Соединение таблиц (join)

  • Выполнение подзапроса (subquery)

  • Агрегирующие функции (aggregate functions)

И в первую очередь это схема хранения данных и ее маппинг на реляционную модель.

Аудит имеющейся структуры БД

На каком-то этапе команды сталкиваются с необходимостью верхнеуровневого взгляда на работу с данными:

  • Наглядно представить набор коллекций, атрибутов, типов, наличие вложенных структур и массивов для всего проекта

  • Идентифицировать коллекции и атрибуты, содержащие пользовательские данные (PII)

  • Обнаружить избыточное и дублирующее хранение

  • Разделить зоны ответственности команд

findOne() – самый примитивный подход

В случае самого простого и быстрого решения, наша задача сводится к следующим действиям:

  1. Вывести список БД

  2. Отобразить список коллекций

  3. Для каждой коллекции найти документ и показать его схему

Выглядеть это может следующим образом:

show dbs // show list of databases
use mydb // switch to the database you want to query
show collections // list all collections in the database
db.collectionName.findOne().pretty() // show a single document in the database in a readable format
 
{
   _id: ObjectId("558448a20294464239ae9f8a"),
   name: 'Goroka',
   city: 'Goroka',
   country: 'Papua New Guinea',
   iatacode: 'GKA',
   icaocode: 'AYGA',
   latlon: [ -6.081689, 145.391881 ]
}

А теперь еще чуть более наглядно – вывести список атрибутов и их типы:

var schematodo = db.collection_name.findOne()
for(var key in schematodo) { print (key, typeof schematodo[key]); }
 
_id object
name string
city string
country string
iatacode string
icaocode string
latlon object

Однако у этого подхода есть недостатки, и весьма значительные:

  • Результат мы получаем на основании всего одного документа, и это отнюдь не значит, что все остальные документы обладают такой же схемой

  • Все заботы об автоматизации и парсинге результатов ложатся на плечи инженера

Использование специализированных приложений

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

  • Использование парадигмы Map Reduce для анализа схемы данных

  • Гибкие настройки: вы решаете, какие документы и в каком количестве необходимо проанализировать

  • Возможность построения гистограмм частотности значений в коллекциях

  • Простой и удобный cli-интерфейс

  • Выбор формата экспорта данных: json, yaml, table

Лучшим из приложений для анализа схемы MongoDB сегодня является проект Mongoeye (Go) – последнее обновление в марте 2021.

Демонстрация работы Mongoeye
Демонстрация работы Mongoeye

Простое использование, конфигурирование с помощью флагов: 

mongoeye [host] database collection [flags]

Экспорт доступен в таблицу окна терминала, и во внешний файл json/yaml.

Помимо этого mongoeye поможет построить гистограмму распределения значений атрибута:

valueHistogram:
 start: 2.5
 end: 12
 range: 9.5
 step: 0.5
 numOfSteps: 19
 intervals: [36, 25, 14, 81, 95, 86, 59, 6, 82, 84, 62, 33, 19, 9, 1, 14, 67, 2, 45]
Визуализация гистограммы распределения значений атрибута построенная с помощью Mongoeye
Визуализация гистограммы распределения значений атрибута построенная с помощью Mongoeye

Еще один заметный проект – Variety (JS). Последнее обновление – 2018 год.

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

# Analyze Only Recent Documents
$ mongo test --eval "var collection = 'users', limit = 1" variety.js
 
# Analyze Documents to a Maximum Depth
$ mongo test --eval "var collection = 'users', maxDepth = 3" variety.js
 
# Analyze a Subset of Documents
$ mongo test --eval "var collection = 'users', query = {'caredAbout':true}" variety.js
 
# Analyze Documents Sorted In a Particular Order
$ mongo test --eval "var collection = 'users', sort = { updated_at : -1 }" variety.js
 
# Include Last Value
$ mongo test --eval "var collection = 'orders', lastValue = true" variety.js

Утилита mongodrdl от MongoDB

Эта утилита входит в состав компонентов MongoDB Connector for BI и предназначена она для управления маппингом схемы MongoDB на реляционную. Сегодня mongodrdl интересна нам как отдельная утилита, способная:

  • Формировать схемы на основе содержимого документов ряда коллекций

  • Выгружать схемы в файлы .drdl (yaml-like)

  • Управлять файлами схем .drdl – просмотр, присваивание имени, версионирование, обновление, удаление

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

# prepare list of databases
 declare -a DATABASES=(
   "documents"
   "communication"
   "flights"
   )
  
# loop through databases and generate schemas to yaml files   
   for db in "${DATABASES[@]}"
   do
   mongodrdl \
       --host=<host_address> \
       --port=<port> \
       --db=$db \
       --username=<username> \
       --password=<password> \
       --out=./$db.yml \
       --sampleSize=10000 # choose number of documents to be sampled
   done

Формат Document Relational Definition Language

Файлы DRDL определяют реляционное представление схемы MongoDB.

В предыдущем абзаце мы получили ряд таких файлов. Общая структура файла выглядит следующим образом:

schema:
- db: <database name>
 tables:
 - table: <SQL table name>
   collection: <MongoDB collection name>
   pipeline:
   - <optional pipeline elements>
   columns:
   - Name: <MongoDB field name>
     MongoType: <MongoDB field type>
     SqlName: <mapped SQL column name>
     SqlType: <mapped SQL column type>

Впоследствии эти файлы могут быть использованы утилитой mongosqld для ответов на запросы языка SQL (из BI-инструментов, например).

Анализ полученных метаданных

Для целей аудита и обзора данных, хранящихся в MongoDB можно сформировать единый документ, например с помощью pandas.

import yaml
import pandas as pd
import glob
 
yml = glob.glob('*.yml')
 
s = []
 
for y in yml:
   with open(y, 'r') as f:
       s += yaml.load(f, Loader=yaml.FullLoader)['schema']
 
df = pd.io.json.json_normalize(s,
                              record_path=['tables', 'columns'],
                              meta=['db', ['tables', 'table'], ['tables', 'collection']],
                              record_prefix='column.',
                              meta_prefix='database.')

Полная версия ipython notebook доступна на Github Gist – Export and analyse MongoDB schema to relational view.

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

 {
   _id: ObjectId("5df740b7823773cd52a3d137"),
   localized_names: [ { locale: 'en', name: 'Bagotville' } ],
   iata_code: 'YBG'
 }

Обратите внимание на ключ localized_names. В качестве значения он содержит массив элементов. А теперь посмотрим, как это отражается в сгенерированной mongodrdl схеме:

Реляционная схема для коллекции MongoDB с массивов вложенных документов
Реляционная схема для коллекции MongoDB с массивов вложенных документов

Для каждого массива создается поле с префиксом _idx содержащее индекс (порядковый номер) элемента массива. Ключи вложенных документов перечисляются с помощью dot notation (через точку). 

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

NoSQL базы данных – часть стека Инженера Данных

Работа с данными – одно из наиболее востребованных и бурно развивающихся направлений. Каждый день я нахожу новые интересные задачи и придумываю решения для них. Это захватывающий и интересный путь, расширяющий горизонты.

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

  • Data Architecture

  • Data Lake

  • DWH

  • NoSQL/NewSQL

  • MLOps

В рамках курса студентам предлагаются практические навыки не только по document-oriented базам данных (MongoDB, CouchDB), но и key-value (Redis, Aerospike), full-text search (ELK).

Модуль 4 NoSQL/NewSQL в программе Инженер Данных
Модуль 4 NoSQL/NewSQL в программе Инженер Данных

Подписывайтесь и следите за моими вебинарами и публикациями в телеграм-канале Technology Enthusiast.

Благодарю за внимание.

Комментарии (0)