Связь "многие ко многим" с базой данных NoSQL


Я хочу реализовать структуру таксономии (географические термины) для моего узла.JS-приложение с базой данных NoSQL. У меня была похожая структура таксономии с MySQL, но пришло время двигаться вперед и изучать что-то новое, поэтому я решил попробовать другой подход и использовать NoSQL (ориентированный на документы) для моего тестового приложения. Структура таксономии проста - существует пять различных уровней: страна (т. е. Великобритания) → регион (Англия) → графство (Мерсисайд) → город/городок / деревня (Ливерпуль) → часть города (Ливерпуль). город (Токстет).

Очевидный выбор-использовать древовидную структуру, но дьявол кроется в деталях - исторически некоторые города и поселки принадлежали другим графствам. Идея заключалась в том, чтобы помечать людей, родившихся в определенных городах или поселках, этими терминами и фильтровать их позже по геотегам, поэтому я должен уважать тот факт, что Ливерпуль или Манчестер (среди прочих) были частью Ланкашира в то время, когда некоторые люди родились. В противном случае результат, полученный любым пользователем с помощью моего геофильтра, будет неверным. Пример: Джон Доу родился в Блэкберне (Ланкашир) в далеком 1957 году. Пол Браун родился в 1960 году в Ливерпуле (Ланкашир, ныне Мерсисайд). Джорджия Доу (урожденная Джонс) родилась в Виррале (Чешир, ныне Мерсисайд) 5 лет спустя. Их сын Ринго родился в Ливерпуле (Мерсисайд к тому времени) в 1982 году. Джон-Ланкастер по рождению, пол-Ланкастер и Мерсисайдер, Джорджия-из Чешира и Мерсисайда одновременно, Ринго-из Мерсисайда. Так и должно быть классифицированы соответственно, когда я ищу по округу. Но с простой структурой "один ко многим", которая соответствует современной структуре страны, они никогда не будут фильтроваться так, как должны быть.

Как реализовать коллекцию с учетом сложности ее структуры с помощью NoSQL (в первую очередь документоориентированных) решений? Я погуглил его и сделал некоторые исследования над стеком*, но все еще не имел понятия, что с ним делать дальше. На мой взгляд, есть несколько возможных способов решить эту проблему.:

  1. Используйте 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]},
    }
    
  2. Используйте древовидную структуру с некоторыми ссылками:

    {    
        {'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},
            },
        },
    }
    
  3. Используйте древовидную структуру без ссылок (один ко многим) и добавьте тег" альтернативный родитель " в документ вручную:

    {    
        {'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},
            },
        },
    }
    
  4. Придерживайтесь SQL.

  5. попробуйте реализовать таксономию без баз данных.

Дайте мне совет по этому вопросу, пожалуйста. Я новичок с любым NoSQL (в настоящее время я не разрабатывал таких баз данных) так что для меня существует реальная проблема дизайна.

И я новичок в stack* так что не стесняйтесь поправлять меня, если я сделал что-то не так с этим сообщением :) спасибо!

EDIT Я выбрал @Jonathan answer в качестве решения. Я думаю, что это лучше подходит для моих нужд (там будут другие документы, чтобы хранить в моей базе данных и помечать их этими терминами), особенно с функциональностью mapReduce, предложенной @Valentyn.

Но если нет коллекций документов, необходимых для вашего приложения, график база данных (основанная на отношениях, а не на документах), предложенная @Philipp, вероятно, является лучшим возможным решением.

2 15

2 ответа:

Во-первых, выбор между NoSQL и базой данных SQL затруднен, если вы не знакомы с основными принципами. Если это единственные данные, которые вы храните, перейдите к реляционному (SQL). Если есть больше данных (что я предполагаю), и это требует больше переплетенной схемы, придерживайтесь NoSQL hands down.

Я бы выбрал реляционный маршрут, чтобы он не был слишком сложным... начните несколько коллекций; одна для стран, регионов и так далее. Не расстраивайтесь из-за реляционных отношений (SQL) схемы типов в базе данных NoSQL; в большинстве случаев они являются лучшим решением.

Затем в каждой из подгрупп есть поле, которое называет родителя.

Например:

{
    {'name': 'United Kingdom'},
    {'name': 'United States'}
}

{
    {'name': 'England', 'parent': 'United Kingdom'},
    {'name': 'California', 'parent': 'United States'}
}

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

Удачи вам!

EDIT: отвечая на вопросы OP:

(Во-первых, я бы рекомендовал MongoDB - это отличное решение для всех.)

  1. Потому что, когда вы начнете работать с MongoDB, вы поймете, что он хранит данные бок о бок на жестком диске. Если вы отредактируете такую огромную запись, она, скорее всего, будет отодвинута на заднюю часть диска, что сделает ваш жесткий диск похожим на швейцарский сыр. Как только вы доберетесь до этой точки, вам придется сделать ремонт, чтобы сконденсировать его еще раз. Кроме того, таким образом данные легче разделяются в вашем приложении, таким образом, если вам нужно сделать что-то с данными, вам не придется применять их ко всему объекту. Я предполагаю, что у вас будет большой набор данных, так как в мире есть много разных мест.

  2. Не беспокойтесь слишком сильно о таких вещах. Вы можете использовать ID для родителя и сопоставлять детей с ID, если планируете часто менять имена. Я просто сделал это таким образом, потому что предполагал, что вам не нужно будет менять базу данных о местоположении.

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

    {
        {
            'name': 'England,
            'parent': {
                1: 1,
                568: 1
            }
         }
     }
    

Таким образом, вы можете использовать свою идею индексов и найти, где db.region.$.568 = 1

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

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

  2. И 3. Один документ, который представляет собой огромное дерево, - это не очень хорошая идея. либо потому, что MongoDB имеет ограничение в 16 Мб на документ. Когда вы создаете огромные монолитные документы, вы можете достичь этого предела.

Я думаю, что MongoDB не может быть лучшим решением для вашего варианта использования. Вы рассматривали возможность использования Графовой базы данных ? MongoDB оптимизирован для автономных документов, которые стоят сами по себе. Но основное внимание в графовых базах данных уделяется наборам данных, в которых имеется множество сущностей, определяемых их отношениями к другим сущностям. Этот взгляд очень похоже на ваш прецедент.