Вопрос

Каковы наилучшие методы хранения вложенных наборов (например, деревьев комментариев) в 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" },
   ]
}

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

Другим способом сделать это было бы с помощью массивов

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

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

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

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

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

нашел бы всех детей "а"

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

Обновить

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

    db.test.find({путь:{$в:["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 является вашим корневым элементом или присутствует в большинстве ваших записей, то вы выполняете почти полное сканирование записей вместо эффективного индексного запроса.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top