MongoDB вложенные наборы - PullRequest
       14

MongoDB вложенные наборы

7 голосов
/ 06 декабря 2009

Как лучше хранить вложенные множества (например, деревья комментариев) в MongoDB?

Я имею в виду, что каждый комментарий может иметь родительский комментарий и дочерние комментарии (ответы).

Хранить их так:

{
   title: "Hello",
   body: "Please comment me!",
   comments: [
        {
            author: "Peter",
            text: "Hi there",
            answers: [
                  {
                      author: "Peter",
                      text: "Hi there",
                      answers: [
                                 { author: "Ivan", text: "Hi there" },
                                 { author: "Nicholas", text: "Hi there" }
                      ]
                  },
                  { author: "Ivan", text: "Hi there" },
                  { author: "Nicholas", text: "Hi there" },
            ]
        },
        { author: "Ivan", text: "Hi there" },
        { author: "Nicholas", text: "Hi there" },
   ]
}

не круто, потому что мы не можем, например, попросить "все посты, которые прокомментировал Питер" без карты / уменьшить.

Ответы [ 2 ]

3 голосов
/ 06 декабря 2009

Я думаю, что нет идеального решения - зависит от того, какие операции важнее для вашего приложения. Я считаю, что Silicon Alley Insider хранит комментарии, вложенные, например, в MongoDB. Это усложняет запрос, о котором вы упоминаете.

Один из вариантов - сохранить на верхнем уровне в публикации список всех комментариев в массиве. Думайте об этом как о денормализованных данных. Тогда можно легко найти все посты, в которых участвует определенный комментатор. Затем, чтобы перейти к детализации, вы используете map / reduce или db.eval (), чтобы получить вложенную информацию поста в.

Еще одно замечание - если вы работаете с одним документом, db.eval (), вероятно, легче, чем map / lower. $ where также является опцией, но может быть медленным, поэтому мне нравится дополнительный «список комментариев», упомянутый выше - не так же легко индексировать и этот массив (см. «Multikey» в документации).

Смотрите также: http://groups.google.com/group/mongodb-user/browse_thread/thread/df8250573c91f75a/e880d9c57e343b52?lnk=gst&q=trees#e880d9c57e343b52

2 голосов
/ 14 сентября 2010

В ссылке из поста Дмайта Мерримана упоминается использование ключа пути и сопоставление регулярных выражений

{
  path : "a.b.c.d.e.f"
}

Еще один способ сделать это - с массивами

{
  path : ["a", "b", "c", "d", "e", "f"]
}

db.test.ensureIndex({path: 1})

это должно сделать это довольно быстро.

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

db.test.find({path: "a"})

найдет всех детей "a"

Вместо имен путей я бы, вероятно, использовал _id узлов.

Обновление

  • Остерегайтесь одной вещи - индекс может содержать только один массив.
  • Будьте осторожны, используя объяснения в ваших запросах

    db.test.find ({путь: {$ in: ["a", "b"]})

дает вам

 db.test.find({path: {$in: ["a", "b"]}}).explain()
{
        "cursor" : "BtreeCursor path_1 multi",
        "nscanned" : 2,
        "nscannedObjects" : 2,
        "n" : 1,
        "millis" : 0,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "isMultiKey" : true,
        "indexOnly" : false,
        "indexBounds" : {
                "path" : [
                        [
                                "a",
                                "a"
                        ],
                        [
                                "b",
                                "b"
                        ]
                ]
        }
}

но

 db.test.find({path: {$all: ["a", "b"]}}).explain()
{
        "cursor" : "BtreeCursor path_1",
        "nscanned" : 1,
        "nscannedObjects" : 1,
        "n" : 1,
        "millis" : 0,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "isMultiKey" : true,
        "indexOnly" : false,
        "indexBounds" : {
                "path" : [
                        [
                                "a",
                                "a"
                        ]
                ]
        }
}

использует только первый элемент, а затем сканирует все подходящие результаты для b.
Если a является вашим корневым элементом или присутствует в большинстве ваших записей, вы выполняете почти полное сканирование записей вместо эффективного запроса индекса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...