Статьи

MongoDB из окопов: мазохистские вложенные коллекции

MongoDB поддерживает многофункциональные документы, которые могут включать, среди прочего, встроенные документы. Эта функция довольно хорошо воплощает отношение has-a и может, при правильном моделировании, уменьшить количество операций поиска, необходимых для определения определенных данных, поскольку в Mongo нет соединений.

Классическим примером встраивания коллекции документов в родительский документ являются контактные адреса (например, почтовые адреса, электронная почта, твиттер и т. Д.), Связанные с человеком. Думай визитки. Конечно, вы можете смоделировать это любым количеством способов — в традиционном реляционном мире это будет отношение один ко многим, по крайней мере, между двумя таблицами. Тем не менее, с базой данных, ориентированной на документы, вы можете моделировать родительский документ со встроенной коллекцией contacts , каждый из которых является документом, содержащим, скажем, тип (например, телефон, твиттер, электронная почта) и значение (которое может быть 555-555- 555, @jon_doe и т. Д.).

Эти отношения с Mongo работают хорошо, если дочерний внедренный документ никогда не должен существовать вне его родителя . Например, в случае визитной карточки контактный документ, представляющий номер телефона, не обязательно имеет смысл вне контекста лица, которому он принадлежит. Благодаря этим отношениям вы можете легко найти конкретного человека по его / ее номеру телефона (то есть, с помощью языка запросов Монго, вы можете легко получить доступ к внутренним массивам через его точечное представление ). И, когда у вас есть справка к человеку, вам не нужно выполнять серию находок, чтобы выяснить контактную информацию — все в порядке.

Тем не менее, вещи начинают быстро становиться болезненными, если вы хотите работать исключительно с отдельным вложенным документом. То есть, если вы выполняете находки, предназначенные для работы с ожидаемым результирующим внедренным документом, вас ожидает некоторая работа: начиная с Mongo 2.2, вы не можете выбрать отдельный документ из коллекции, находящейся в родительском объекте, через запрос. Находка в этом случае потянет все — это зависит от вас (то есть вашего приложения), чтобы отфильтровать вещи.

Пример, вероятно, поможет: представьте пример визитной карточки из более раннего документа — person содержащего встроенную коллекцию contacts :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
{
  first_name: 'Andrew',
  last_name: 'Glover',
  contacts: [
             {
              type: 'cell',
              value: '555-555-5555',
              last_updated: 2012-09-01 23:41:51 UTC
             },
             { type: 'home',
               value: '555-555-5551',
               last_updated: 2012-02-11 12:21:11 UTC
             }
            ]
}

Найти этот документ по номеру телефона легко:

1
db.persons.find({'contacts.value':'555-555-5555'})

Но что, если вы хотите найти недавно обновленный contact , скажем, с начала месяца, и изменить его значение или добавить дополнительные метаданные? Запрос, который вы хотели бы выглядеть примерно так:

1
db.persons.find({'contacts.last_updated': {$gte: datetime(2012, 8, 1)}})

При желании вы можете добавить ограничители запросов (например, {contacts:1} ), которые будут просто возвращать документ пользователя только с набором contacts . Таким образом, вам остается перебирать итоговую коллекцию contacts и работать со своей магией таким образом. То есть вам все еще нужно найти контактный документ, который был отредактирован в этом месяце! В вашем коде!

Ничего страшного, говоришь? Этот конкретный пример, действительно, немного надуманен; однако представьте, если общий документ достаточно большой (может быть, это не person а organization !) и что встроенная коллекция также длинна (сколько сотрудников у Google?). Теперь это простое обновление протягивает много байтов по проводам (и в процессе обременяет Монго), а затем ваше приложение работает с большим количеством байтов в памяти (теперь документ облагает налогом ваше приложение!). Вы хотели, чтобы эта операция происходила быстро и под нагрузкой?

Таким образом, в случае встроенных коллекций документов, если вы предполагаете работать с конкретным встроенным документом изолированно , на данном этапе лучше смоделировать взаимосвязи с различными коллекциями (т. Е. В этом примере жизнь будет намного проще, если есть person коллекция и contacts ). Действительно, гибкость ориентированных на документы хранилищ данных без схем является благом для быстрой эволюционной разработки. Но вы все еще должны подумать заранее. Если, конечно, вы не мазохист.

Я большой поклонник Монго. Ознакомьтесь с некоторыми из статей, видео и подкастов, которые я сделал, которые посвящены Монго, в том числе:

Ссылка: MongoDB Из окопов: врезанные мазохистские коллекции от нашего партнера JCG Эндрю Гловера в блоге The Disco Blog .