MongoDB предпочтительная схема для встроенных коллекций. документы по сравнению с массивами

Я считаю, что есть хотя бы два способа иметь встроенные данные в документе mongodb. В упрощенном случае мы могли бы иметь что-то вроде этого:

{
    'name' : 'bill',
    'lines': {
       'idk73716': {'name': 'Line A'},
       'idk51232': {'name': 'Line B'},
       'idk23321': {'name': 'Line C'}
    }
}

и как массив:

{
    'name' : 'bill',
    'lines': [
       {'id': 'idk73716', 'name': 'Line A'},
       {'id': 'idk51232', 'name': 'Line B'},
       {'id': 'idk23321', 'name': 'Line C'}
    ]
}

Как вы можете видеть в этом случае, важно сохранить идентификатор каждой строки.

Мне интересно, есть ли плюсы и минусы между этими двумя схемами. Особенно, когда речь заходит об использовании индексов, я чувствую, что второй может быть проще работать, поскольку можно было бы создать индекс на 'lines.id' или даже 'lines.name' для поиска идентификатора или имени по всем документам. Я не нашел никакого рабочего решения для индексации идентификаторов ('idk73716' и т.д.) В первом примере.

Как правило, предпочтительнее использовать второй подход, если у вас есть пример использования?

Ответы

Ответ 1

В вашем первом подходе вы не можете индексировать поля id, так как id используется как ключ. Его тип действует как словарь ключевых значений. Этот подход полезен, если у вас есть известный набор идентификаторов (конечно, меньшее число). В первом примере id хорошо известен спереди,

>>db.your_colleection.find()
 { "_id" : ObjectId("4ebbb6f974235464de49c3a5"), "name" : "bill", 
  "lines" : { 
             "idk73716" : { "name" : "Line A" },
             "idk51232" : { "name" : "Line B" } ,
             "idk23321":  { "name" : "Line C" }
            } 
  }

чтобы найти значения для id idk73716, вы можете сделать это с помощью

 db.your_colleection.find({},{'lines.idk73716':1})
 { "_id" : ObjectId("4ebbb6f974235464de49c3a5"), "lines" : { "idk73716" : { "name" : "Line A" } } }

пустой {} обозначает запрос, а вторая часть {'lines.idk73716': 1} - это селектор запросов.

, имеющий идентификаторы как ключи, имеющие преимущество в выборе отдельного поля. Даже если {'lines.idk73716': 1} является селектором полей, здесь он служит в качестве запроса и селектора. но это не может быть сделано в вашем втором подходе. Предположим, что вторая коллекция похожа на это

> db.second_collection.find()
{ "_id" : ObjectId("4ebbb9c174235464de49c3a6"), "name" : "bill", "lines" : [
    {
        "id" : "idk73716",
        "name" : "Line A"
    },
    {
        "id" : "idk51232",
        "name" : "Line B"
    },
    {
        "id" : "idk23321",
        "name" : "Line C"
    }
] }
> 

И вы проиндексировали идентификатор поля, поэтому, если вы хотите запросить идентификатор

> db.second_collection.find({'lines.id' : 'idk73716' })

{ "_id" : ObjectId("4ebbb9c174235464de49c3a6"), "name" : "bill", "lines" : [
    {
        "id" : "idk73716",
        "name" : "Line A"
    },
    {
        "id" : "idk51232",
        "name" : "Line B"
    },
    {
        "id" : "idk23321",
        "name" : "Line C"
    }
] }
> 

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

см.

db.second_collection.find({'lines.id' : 'idk73716' },{'lines':1})

будет извлекать все строки, а не только idk73716

{ "_id" : ObjectId("4ebbb9c174235464de49c3a6"), "lines" : [
    {
        "id" : "idk73716",
        "name" : "Line A"
    },
    {
        "id" : "idk51232",
        "name" : "Line B"
    },
    {
        "id" : "idk23321",
        "name" : "Line C"
    }
] }

Надеюсь, что это поможет

ИЗМЕНИТЬ

Благодаря @Gates VP для указания

db.your_collection.find({'lines.idk73716':{$exists:true}}). если ты хотите использовать версию "идентификаторы как ключи", запрос существует, но он не будет индексироваться

Мы все еще можем использовать $exists для запроса id, но он не будет индексироваться

Ответ 2

Сегодня у нас есть оператор $eleMatch для этого, как обсуждалось здесь - Получить только запрошенный элемент в массиве объектов в коллекции MongoDB

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

Я нашел, легко выполнить CRUD с новыми операторами $set/$unset, на встроенных документах, когда идентификаторы используются как имена свойств. И если клиент может получить идентификатор для внесения изменений, он лучше, чем массив, IMO. Вот еще один полезный blogpost от Mongodb о разработке схемы и принятии этих проектных решений.

http://blog.mongodb.org/post/87200945828/6-rules-of-thumb-for-mongodb-schema-design-part-1