Основы
Итак, в основном я написал программу, которая генерирует тестовые данные для MongoDB в Node.
Я дал щедрость на этот вопрос, чтобы получить больше ответов. Чтобы проверить текущее решение, пожалуйста, прокрутите вниз до цитаты ниже!
Проблема
Для этого программа считывает файл схемы и генерирует из него указанное количество тестовых данных. Проблема в том, что эти данные могут в конечном итоге стать достаточно большими (подумайте о создании 1M пользователей (со всеми необходимыми им свойствами) и 20M сообщений чата (с userFrom
и userTo
), и они должны хранить все это в оперативной памяти, чтобы измените / преобразуйте / отобразите его и после этого сохраните в файл.
Как это работает
Программа работает так:
- Чтение файла схемы
- Создать тестовые данные из схемы и сохранить их в структуре (структура приведена ниже)
- Запустите эту структуру и свяжите все объекты
referenceTo
со случайным объектом с соответствием referenceKey
.
- Преобразование структуры объекта в
string[]
операторов вставки MongoDB
- Сохраните это
string[]
в файле.
Это структура сгенерированных тестовых данных:
export interface IGeneratedCollection {
dbName: string, // Name of the database
collectionName: string, // Name of the collection
documents: IGeneratedDocument[] // One collection has many documents
}
export interface IGeneratedDocument {
documentFields: IGeneratedField [] // One document has many fields (which are recursive, because of nested documents)
}
export interface IGeneratedField {
fieldName: string, // Name of the property
fieldValue: any, // Value of the property (Can also be IGeneratedField, IGeneratedField[], ...)
fieldNeedsQuotations?: boolean, // If the Value needs to be saved with " ... "
fieldIsObject?: boolean, // If the Value is a object (stored as IGeneratedField[]) (To handle it different when transforming to MongoDB inserts)
fieldIsJsonObject?: boolean, // If the Value is a plain JSON object
fieldIsArray?: boolean, // If the Value is array of objects (stored as array of IGeneratedField[])
referenceKey?: number, // Field flagged to be a key
referenceTo?: number // Value gets set to a random object with matching referenceKey
}
Фактические данные
Таким образом, в примере с 1M Users и 20M сообщениями это будет выглядеть так:
- 1x IGeneratedCollection (
collectionName = "users"
)
- 1Mx IGeneratedDocument
- 10x IGeneratedField (например, у каждого пользователя есть 10 полей)
- 1x IGeneratedCollection (
collectionName = "messages"
)
- 20Mx IGeneratedDocument
- 3x IGeneratedField (
message, userFrom, userTo
)
что приведет к 190M экземплярам IGeneratedField
(1x1Mx10 + 1x20Mx3x = 190M
).
Заключение
Это, очевидно, очень много для обработки оперативной памяти, поскольку она должна хранить все это одновременно.
Временное решение
Теперь это работает так:
- Генерируйте 500 документов (строк в sql) одновременно
JSON.stringify
этих 500 документов и поместите их в таблицу SQLite со схемой (dbName STRING, collectionName STRING, значение
JSON)
- Удалите эти 500 документов из JS и позвольте сборщику мусора сделать свое дело
- Повторять до тех пор, пока все данные не будут сгенерированы и в таблице SQLite
- Возьмите одну из строк (каждая из которых содержит 500 документов) за раз, примените
JSON.parse
и найдите в них ключи
- Повторять до тех пор, пока не будут запрошены все данные и не будут получены все ключи.
- Возьмите одну из строк за раз, примените
JSON.parse
и найдите в них ключевые ссылки
- Применить
JSON.stringify
и обновить строку, если необходимо (если ключевые ссылки найдены и разрешены)
- Повторять до тех пор, пока все данные не будут запрошены и все ключи не будут разрешены
- Возьмите одну из строк за раз, примените
JSON.parse
и преобразуйте документы в допустимые вставки sql / mongodb
- Добавление вставки (строки) в таблицу SQLite со схемой (singleInsert STRING)
- Удалить старую и теперь неиспользуемую строку из таблицы SQLite
- Записать все вставки в файл (если они запускаются из командной строки) или вернуть dataHandle для запроса данных в таблице SQLite (если они запускаются из других
узел приложения)
Это решение решает проблему с оперативной памятью, поскольку SQLite автоматически переключается на жесткий диск при заполнении оперативной памяти
НО
Как видите, задействовано много JSON.parse
и JSON.stringify
, что резко замедляет весь процесс
Что я думал:
Может быть, я должен изменить IGeneratedField, чтобы использовать только сокращенные имена в качестве переменных (fieldName
-> fn
, fieldValue
-> fv
, fieldIsObject
-> fio
, fieldIsArray
-> fia
, ....)
Это уменьшит необходимое хранилище в таблице SQLite, НО также затруднит чтение кода
Использовать документно-ориентированную базу данных (но я не нашел ее), чтобы лучше обрабатывать данные JSON
Вопрос
Есть ли лучшее решение для обработки больших объектов, таких какэто в узле?
Мое временное решение в порядке?Что в этом плохого?Можно ли изменить его для улучшения производительности?