Отношение многие ко многим с базой данных NoSQL
Я хочу реализовать структуру таксономии (географические термины) для моего приложения node.js с базой данных NoSQL. У меня была похожая структура таксономии с MySQL, но пришло время двигаться вперед и изучать что-то новое, поэтому я решил попробовать другой подход и использовать NoSQL (ориентированный на документы) для своего тестового приложения. Структура таксономии проста - существует пять различных уровней: страна (т.е. Великобритания) → регион (Англия) → округ (Мерсисайд) → город / поселок (Ливерпуль) → часть города (Токстет).
Очевидный выбор - использовать древовидную структуру, но дьявол кроется в деталях - исторически некоторые города принадлежали другим округам. Идея состояла в том, чтобы пометить людей, которые родились в определенных городах или поселках, с этими терминами и отфильтровать их позже по геотегам, поэтому я должен учитывать тот факт, что Ливерпуль или Манчестер (среди прочих) были частью Ланкашира в то время, когда некоторые люди родились, В противном случае результат, полученный любым пользователем с помощью моего геофильтра, будет неверным.
Пример: Джон Доу родился в Блэкберне (Ланкашир) в 1957 году. Пол Браун родился в 1960 году в Ливерпуле (Ланкашир, теперь Мерсисайд). Джорджия Доу (урожденная Джонс) родилась в Виррале (Чешир, теперь Мерсисайд) 5 лет спустя. Их сын Ринго родился в Ливерпуле (к тому времени Мерсисайд) в 1982 году.
Джон - ланкастерец по происхождению, Пол - ланкастерец и Мерсисидер, Грузия - из Чешира и Мерсисайда, Ринго - из Мерсисайда. Таким образом, они должны быть классифицированы соответственно, когда я ищу по округе. Но с простой структурой "один ко многим", которая следует современной структуре страны, они никогда не будут отфильтрованы, как это должно быть.
Как реализовать коллекцию, учитывая сложность ее структуры, с помощью решений NoSQL (прежде всего ориентированных на документы)? Я гуглил его и провел некоторое исследование стека *, но все еще не знал, что делать дальше. На мой взгляд, есть несколько возможных способов ее решения:
Используйте SQL-подобную структуру данных:
{ {'name': 'United Kingdom', 'unique_id': 1}, {'name': 'England', 'unique_id': 2, 'parents': [1]}, {'name': 'Merseyside', 'unique_id': 3, 'parents': [2]}, {'name': 'Lancashire', 'unique_id': 4, 'parents': [2]}, {'name': 'Liverpool', 'unique_id': 5, 'parents': [3, 4]}, }
Используйте древовидную структуру с некоторыми ссылками:
{ {'name': 'United Kingdom', 'unique_id': 1 {'name': 'England', 'unique_id': 2] {'name': 'Merseyside', 'unique_id': 3] {'name': 'Liverpool', 'unique_id': 5, 'alternate_parents': [4]}, }, {'name': 'Lancashire', 'unique_id': 4}, }, }, }
Используйте древовидную структуру без ссылок (один ко многим) и добавьте тег "альтернативный родительский" в документ вручную:
{ {'name': 'United Kingdom', 'unique_id': 1 {'name': 'England', 'unique_id': 2] {'name': 'Merseyside', 'unique_id': 3] {'name': 'Liverpool', 'unique_id': 5}, }, {'name': 'Lancashire', 'unique_id': 4}, }, }, }
Придерживайтесь SQL.
- Попробуйте внедрить таксономию без базы данных.
Дайте мне совет по этому вопросу, пожалуйста. Я новичок в любом NoSQL (в настоящее время я не проектировал таких баз данных), поэтому для меня есть реальная проблема дизайна.
И я новичок в стеке *, поэтому не стесняйтесь поправлять меня, если я сделал что-то не так с этим постом:) Спасибо!
РЕДАКТИРОВАТЬ Я выбрал @Jonathan ответ в качестве решения. Я думаю, что это лучше подходит для моих нужд (в моей базе данных будут храниться другие документы и помечать их этими терминами), особенно с функциональностью mapReduce, предложенной @Valentyn.
Но если для вашего приложения не нужны коллекции документов, база данных графиков (основанная на отношениях, а не документах), предложенная @Philipp, вероятно, является наилучшим возможным решением.
2 ответа
Во-первых, выбирать между NoSQL и базой данных SQL сложно, если вы не знакомы с основными принципами. Если это единственные данные, которые вы храните, используйте реляционный (SQL). Если есть больше данных (что я предполагаю), и это требует больше переплетенной схемы, придерживайтесь NoSQL руками вниз.
Я бы выбрал для этого реляционный путь, чтобы он не становился слишком сложным... запустил несколько коллекций; один для стран, регионов и так далее. Не отчаивайтесь делать схемы реляционного (SQL) типа в базе данных NoSQL; большую часть времени они являются лучшим решением.
Затем в каждой из подгрупп есть поле, которое называет родителя.
Например:
{
{'name': 'United Kingdom'},
{'name': 'United States'}
}
{
{'name': 'England', 'parent': 'United Kingdom'},
{'name': 'California', 'parent': 'United States'}
}
Таким образом, ваш набор данных не становится настолько вложенным, что возвращаемые данные неуправляемы. Тогда вы можете легко захватить страны и соответствующие регионы... и т.д.
Удачи!
РЕДАКТИРОВАТЬ: Отвечая на вопросы ОП:
(Во-первых, я бы порекомендовал MongoDB - это отличное решение для всех.)
Потому что когда вы начнете работать с MongoDB, вы поймете, что он хранит данные бок о бок на жестком диске. Если вы отредактируете такую огромную запись, скорее всего, она будет перенесена на заднюю часть диска, что сделает ваш жесткий диск похожим на швейцарский сыр. Как только вы доберетесь до этой точки, вам придется сделать ремонт, чтобы еще раз сжать его. Кроме того, таким образом данные легче разделяются в вашем приложении, поэтому, если вам нужно что-то делать с данными, вам не нужно применять их ко всему объекту. Я предполагаю, что у вас будет большой набор данных, так как в мире много разных мест.
Не слишком переживай о таких вещах. Вы можете использовать идентификаторы для родителя и сопоставить детей с идентификатором, если вы планируете много менять имена. Я просто сделал это таким образом, потому что предположил, что вам не нужно менять базу данных местоположений.
Вместо массива я бы использовал вложенный документ для хранения нескольких родителей. Таким образом, его можно будет легко запрашивать и индексировать. Я бы использовал следующий метод:
{ { 'name': 'England, 'parent': { 1: 1, 568: 1 } } }
Таким образом, вы можете использовать свое представление об индексах и найти где db.region.$.568
знак равно 1
Из-за сделанного вами комментария я предполагаю, что вы имеете в виду "MongoDB", когда говорите "NoSQL". Существует множество других технологий баз данных, обычно называемых NoSQL, которые совершенно разные, но, похоже, именно эту вы имеете в виду.
это не очень хорошая идея, потому что для получения всей цепочки таксономии вам нужно будет выполнить несколько запросов к базе данных, которых, как правило, следует избегать.
и 3. Один документ, который представляет собой огромное дерево, также не является хорошей идеей, потому что MongoDB имеет ограничение в 16 МБ на документ. Когда вы создаете огромные монолитные документы, вы можете достичь этого предела.
Я думаю, что MongoDB может быть не лучшим решением для вашего варианта использования. Вы рассматривали возможность использования графической базы данных? MongoDB оптимизирован для автономных документов, которые стоят самостоятельно. Но основное внимание в графовых базах данных уделяется наборам данных, в которых у вас много сущностей, которые определяются их отношениями с другими сущностями. Это очень похоже на ваш вариант использования.