Индексирование Mongodb на N-вложенном объекте

#mongodb

Вопрос:

Предположим, у меня есть коллекция, подобная следующей:

 {
    name: "A",
    age: 50,
    children: [
        {
            name: "B",
            age: 40,
            children: [
                {
                    name: "C",
                    age: 30,
                    children: []
                }
            ]
        }
    ]
},
{
    name: "D",
    age: 60,
    children: []
}
 

Два разных запроса, которые я хотел бы выполнить.

1) Найдите любого, кто соответствует определенному возрасту. Верните корневого пользователя и всех его вложенных дочерних элементов.

бывший)

Если мы запросим возраст = 40, то он вернет объект A и все его вложенные дочерние элементы.

Если мы запросим возраст = 50, то он вернет объект A и все его вложенные дочерние элементы.

Для этой проблемы одним из решений, о котором я думал, было создание другого поля, называемого коллекцией возраста. Он просто сохранит список всех возрастов внутри, а затем я смогу проиндексировать эту коллекцию. Однако я не хочу вручную поддерживать эту коллекцию, так как это было бы очень подвержено ошибкам. Выполнение этого таким образом означает, что каждый раз, когда добавляется новый человек, мне придется добавлять его в коллекцию, и то же самое касается удаления. Есть ли лучший способ сделать это?

2) Найдите кого — нибудь с определенным именем.

бывший)

Если мы запросим name = «C», то он вернет объект C.

Если мы запросим name = «A», то он вернет объект A и все его вложенные дочерние элементы.

Я не слишком уверен, как решить эту проблему. Я полагаю, что могу создать новую коллекцию, содержащую каждую отдельную запись; что-то вроде

 {
    name: "A",
    age: 50,
    children: [
        {
            name: "B",
            age: 40,
            children: [
                {
                    name: "C",
                    age: 30,
                    children: []
                }
            ]
        }
    ]
},
{
    name: "B",
    age: 40,
    children: [
        {
            name: "C",
            age: 30,
            children: []
        }
    ]
},
{
    name: "C",
    age: 30,
    children: []
},
{
    name: "D",
    age: 60,
    children: []
}
 

Но опять же, я не хочу поддерживать копию вручную, и этот подход будет содержать много дубликатов.

Любые мысли будут оценены по достоинству. Спасибо!

Комментарии:

1. Достаточно ли вы гибки, чтобы изменить структуру данных сбора?

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

Ответ №1:

Один из подходов заключается в использовании проекции в вашем запросе

Вот пример:

Для запроса: Найдите любого, кто соответствует определенному возрасту.

Вы можете добавить поле со списком всех возрастов, чтобы сохранить этот список, вы можете использовать триггер базы данных

Ознакомьтесь с этой документацией по триггеру

Для запроса: Найдите кого-нибудь с определенным именем.

 db.collection.find({
  name: "A"
},
{
  children: 0
})
 

Ссылка на игровую площадку Mongo для проверки запроса: Игровая площадка Mongo

Предложение:

Лучше просто сохранить ссылку, а не хранить весь документ детей

Коллекция может выглядеть так

  [
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "age": 50,
    "name": "A",
    children: [
      "B"
    ]
  },
  {
    "_id": ObjectId("5a934e000102030405000001"),
    "age": 40,
    "name": "B",
    children: [
      "C"
    ]
  },
  {
    "_id": ObjectId("5a934e000102030405000002"),
    "age": 30,
    "name": "C",
    children: []
  },
  {
    "_id": ObjectId("5a934e000102030405000003"),
    "age": 60,
    "name": "D",
    children: []
  }
]
 

Чтобы найти детей, вы можете использовать $graphLookup вот так

 db.collection.aggregate([
  {
    $graphLookup: {
      from: "collection",
      startWith: "$children",
      connectFromField: "children",
      connectToField: "name",
      depthField: "depth",
      as: "children"
    }
  },
  {
    "$project": {
      "children.children": 0
    }
  }
])
 

Ссылка на игровую площадку Mongo для проверки запроса: Игровая площадка Mongo

Комментарии:

1. Спасибо за ответ. Извините, если я не был ясен, но для «Найти кого-либо, соответствующего определенному возрасту», он также должен искать детей. Например, если я ищу возраст=30, он должен возвращать C. Предложение «Найти кого-нибудь с определенным именем» выглядит многообещающим. Я еще немного почитаю об этом.

2. Хорошо… есть ли у вас какие-либо ограничения на вложенность? как и у MongoDB docs.mongodb.com/manual/reference/limits/…

3. О, я этого не знал! Но, гнезд будет не так много.

4. Хорошо… Итак, если вы запросите возраст=40 лет, вы хотите только B или B со всеми его детьми?

5. B и все его дети