Доступ к вложенным полям
Документ ReQL представляет собой JSON-объект: набор пар ключ-значение, в котором каждое значение может быть отдельным значением, списком значений или другим набором пар ключ-значение. Когда значение поля содержит дополнительные поля, мы называем их вложенными полями.
Рассмотрим таблицу пользователей с контактной информацией и списком заметок для каждого пользователя в следующем формате:
{
:id => 10001,
:name => "Bob Smith",
:contact => {
:phone => {
:work => "408-555-1212",
:home => "408-555-1213",
:cell => "408-555-1214"
},
:email => {
:work => "bob@smith.com",
:home => "bobsmith@gmail.com",
:other => "bobbys@moosecall.net"
},
:im => {
:skype => "Bob Smith",
:aim => "bobmoose",
:icq => "nobodyremembersicqnumbers"
}
},
:notes => [
{
:date => r.time(2014,1,1,'Z'),
:from => "John Doe",
:subject => "My name is even more boring than Bob's"
},
{
:date => r.time(2014,2,2,'Z'),
:from => "Bob Smith Sr",
:subject => "Happy Second of February"
}
]
}
Контактная информация является вложенной, как пути в файловой системе.
contact → phone → work → 408-555-1212
Вы можете получить значение конкретного поля, используя оператор [] последовательно, чтобы «проникнуть внутрь» вложенности документа:
> r.table('users').get(10001)['contact']['phone']['work'].run(conn)
'408-555-1212'
Большинство команд, принимающих строку имени поля или синтаксис [] выше, также поддерживают вложенный синтаксис в стиле JSON:
> r.table('users').get(10001).pluck(
{'contact' => {'phone' => 'work'}}
).run(conn)
{
'contact' => {
'phone' => {
'work' => '408-555-1212'
}
}
}
В данном примере, когда вы пытаетесь получить только одно значение, синтаксис в стиле JSON не предоставляет существенных преимуществ. Однако вы можете использовать его для извлечения нескольких значений на одном уровне вложенности. Например, вы можете получить только номера телефона и сотовых телефонов Боба, но не домашний:
> r.table('users').get(10001).pluck(
{'contact' => {'phone' => ['work', 'cell']}}
).run(conn)
{
'contact' => {
'phone' => {
'cell' => '408-555-1214',
'work' => '408-555-1212'
}
}
}
Или, рабочий телефон и Skype Боба:
> r.table('users').get(10001).pluck(
{'contact' => [{'phone' => 'work', 'im' => 'skype'}]}
).run(conn)
{
'contact' => {
'im' => {
'skype' => 'Bob Smith'
},
'phone' => {
'work' => '408-555-1212'
}
}
}
И это ещё не всё! Вы можете фильтровать поля объектов внутри списка. Предположим, вам нужны только даты и отправители заметок Боба:
> r.table('users').get(10001).pluck(
{'notes' => ['date', 'from']}
).run(conn)
{
'notes' => [
{
'date' => 2014-01-01 00:00:00 +0000 ,
'from' => 'John Doe'
},
{
'date' => 2014-02-02 00:00:00 +0000 ,
'from' => 'Bob Smith Sr.'
}
]
}
Если вы запросите вложенное поле, которого не существует, вы получите пустой объект или массив (это не то же самое, что и nil значение):
> r.table('users').get(10001).pluck(
{'contact' => [{'phone' => 'work', 'im' => 'msn'}]}
).run(conn)
{
'contact' => {
'im' => { },
'phone' => {
'work' => '408-555-1212'
}
}
}
Обратите внимание, что это поведение также справедливо при извлечении данных из списков. Если вы извлекли subject из notes выше, а у Боба было 10 заметок, 3 из которых не содержали поля subject, вы по-прежнему получите список из 10 объектов: 7 из них будут {subject => <text>}, а 3 — пустыми, то есть { }.
Кроме того, ещё один момент: синтаксис вложенных полей не гарантирует идентичных схем между документами, которые он возвращает. Возможна ситуация, когда путь соответствует объектам с различными схемами, как показано в этом простом примере.
> r.expr([
{
'a' => {
'b' => 1,
'c' => 2
}
},
{
'a' => [
{
'b' => 1,
'c' => 2
}
]
}
]).pluck({'a' => {'b' => true}}).run(conn)
[
{
'a' => {
'b' => 1
}
},
{
'a' => [
{
'b' => 1
}
]
}
]
© RethinkDB contributors
Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
https://rethinkdb.com/docs/nested-fields/ruby/