MongoDB предпочитает схему для встроенных коллекций.документы против массивов - PullRequest
16 голосов
/ 10 ноября 2011

Я полагаю, что есть как минимум два способа встроить данные в документ 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'}
    ]
}

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

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

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

Ответы [ 2 ]

10 голосов
/ 10 ноября 2011

При первом подходе вы не можете индексировать поля 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.

see

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}}).Если вы хотите использовать версию «идентификаторы как ключи», запрос на существование будет работать, но он не будет индексируемым

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

0 голосов
/ 20 апреля 2015

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

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

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

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

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