Манипулируем объектами
Объекты данных
Объекты данных используются для организации структуры сохраняемых данных. Перед тем как вы сможете сохранять данные в объект, вы должны создать объект, делается это при помощи команды object_new, который принимает единственный аргумент - имя объекта. После того как объект создан и до момента его сохранения командой object_save, вы можете работать с полями объекта, а именно записывать значения или список значений в поля командой object_field_set или даже другие объекты, используя специальный параметр в команде object_save. Если вы используете валидационную схему JSON в вашем диггере, команда записи объекта проверит ваш объект на валидность. При наличии валидационных ошибок объект не будет записан. Так же для проверки объекта без записи существует команда object_check, которая просто проверяет объект на валидность и в случае положительного результата исполняет команды из блока do, а в случае отрицательного - из блока else.
Допустимые команды:
# СОЗДАНИЕ ОБЪЕКТА
- object_new: item
# СОХРАНЕНИЕ ПОЛЯ
- object_field_set:
# ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
object: item
# ИМЯ ПОЛЯ В КОТОРОЕ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
# МОЖЕТ БЫТЬ КАК ЯВНЫМ НАПРИМЕР: somefield
# ТАК И СОСТАВНЫМ НАПРИМЕР: somefield_<%somevar%>
field: somefield
# СОХРАНЕНИЕ ПОЛЯ С УКАЗАНИЕМ ТИПА
- object_field_set:
# ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
object: item
# ИМЯ ПОЛЯ В КОТОРОЕ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
# МОЖЕТ БЫТЬ КАК ЯВНЫМ НАПРИМЕР: somefield
# ТАК И СОСТАВНЫМ НАПРИМЕР: somefield_<%somevar%>
field: somefield
# УКАЗЫВАЕМ ТИП ПОЛЯ (МОЖЕТ БЫТЬ: float, date ИЛИ int)
type: float
# И КОЛИЧЕСТВО ЗНАКОВ ПОСЛЕ ЗАПЯТОЙ
precision: 2
# СОХРАНЕНИЕ ДАННЫХ В ПОЛЕ ТИПА json array (PUSH)
- object_field_push:
# ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
object: item
# ИМЯ ПОЛЯ В КОТОРОЕ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
# МОЖЕТ БЫТЬ КАК ЯВНЫМ НАПРИМЕР: somefield
# ТАК И СОСТАВНЫМ НАПРИМЕР: somefield_<%somevar%>
field: somefield
# ПРОВЕРКА ДАННЫХ НА УНИКАЛЬНОСТЬ В ЭТОМ ПОЛЕ (ОПЦИОНАЛЬНО)
# ЕСЛИ ДАННЫЕ УНИКАЛЬНЫ ПРОИСХОДИТ ЗАПИСЬ, ЕСЛИ НЕ УНИКАЛЬНЫ - НЕ ПРОИСХОДИТ
unique: yes
# СОХРАНЕНИЕ ОБЪЕКТА В ОБЪЕКТ
- object_save:
# ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ В ОБЪЕКТ `anotherobj`
name: item
# ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ОБЪЕКТ `item`
to: anotherobj
# ИЛИ
- object_save:
# ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ В ОБЪЕКТ `anotherobj`
name: item
# ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ОБЪЕКТ `item`
to: anotherobj
# ЗАПИСЬ ОБЪЕКТА КАК ТИП json Object (ключ знаение)
as: map
# СОХРАНЕНИЕ ОБЪЕКТА
- object_save:
# ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ
name: item
# ПРОВЕРКА ОБЪЕКТА
- object_check:
# ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ПРОВЕРИТЬ
name: item
# БЛОК КОМАНД, ВЫПОЛНЯЕМЫХ ПРИ ПОЛОЖИТЕЛЬНОМ РЕЗУЛЬТАТЕ ПРОВЕРКИ
do:
- register_set: All is good
# БЛОК КОМАНД, ВЫПОЛНЯЕМЫХ ПРИ ОТРИЦАТЕЛЬНОМ РЕЗУЛЬТАТЕ ПРОВЕРКИ
else:
- exit
Запись объектов в объект может происходить по двум сценариям:
запись множества объектов в поле или запись одного объекта как хеш-таблицы.
Запись множества объектов в объект производится следующим образом:
# СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>'
- to_block
- find:
path: ul
do:
# СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
- object_new: item
- find:
path: li
do:
# СОЗДАДИМ ЕЩЕ ОДИН ОБЪЕКТ НО С ИМЕНЕМ `sub-item`
- object_new: sub-item
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `sub-item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sometext`
- object_field_set:
object: sub-item
field: sometext
# ЗАПИШЕМ ОБЪЕКТ `sub-item` В ОБЪЕКТ `item`
- object_save:
name: sub-item
to: item
# СОХРАНИМ ОБЪЕКТ `item`
- object_save:
name: item
{
"item": {
"sub-item": [
{
"sometext": "A",
},
{
"sometext": "B",
},
{
"sometext": "C",
},
{
"sometext": "D",
}
]
}
}
Запись объекта в объект как json map:
# СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>'
- to_block
- find:
path: ul
do:
# СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
- object_new: item
- find:
path: li
do:
# СОЗДАДИМ ЕЩЕ ОДИН ОБЪЕКТ НО С ИМЕНЕМ `sub-item`
- object_new: sub-item
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `sub-item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sometext`
- object_field_set:
object: sub-item
field: sometext
# ЗАПИШЕМ ОБЪЕКТ `sub-item` В ОБЪЕКТ `item` КАК json map
- object_save:
name: sub-item
to: item
as: map
# ЗАПИШЕМ ОБЪЕКТ `item`
- object_save:
name: item
{
"item": {
"sub-item" : {
"sometext": "D"
}
}
Обратите внимание!
В данном примере сценарий проходит по всем тегам li, но в финальную структуру данных попадает лишь последний элемент со значением D. Это происходит потому что поле будет последовательно перезаписано значениями всех элементов, в результате в поле останется лишь значение последнего элемента.
Пример корректного создания и записи обьектов:
# КАЖДЫЙ РАЗ КОГДА МЫ ИТЕРИРУЕМ ПО БЛОКУ ЛОГИКА ПОВТОРЯЕТСЯ
# И ПОТОМУ КАЖДЫЙ РАЗ БУДЕТ СОЗДАН НОВЫЙ ОБЪЕКТ
- find:
path: .somepath
do:
# СОЗДАЕМ ОБЪЕКТ С ИМЕНЕМ `someobj`
- object_new: someobj
# ЗАПОЛНЯЕМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИСЫВАЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `someobj`
- object_field_set:
object: someobj
field: somefield
# ПЕРЕЙДЕМ В ДРУГОЙ БЛОК И ЗАПИШЕМ ЧТО НИБУДЬ В ДРУГОЕ ПОЛЕ ОБЪЕКТА `someobj`
# ВАЖНО! ЕСЛИ ДРУГОЙ БЛОК ВСЕГО ОДИН - ЗАПИСАННОЕ ЗНАЧЕНИЕ БУДЕТ ВЕРНО,
# ЕСЛИ БЛОКОВ БУДЕТ НЕСКОЛЬКО, ТО В ПОЛЕ БУДЕТ ЗАПИСАНО ЗНАЧЕНИЕ С ПОСЛЕДНЕЙ ИТЕРАЦИИ
# ОБ ЭТОМ ПОДРОБНЕЕ НИЖЕ, СЕЙЧАС ПЕРЕЙДЕМ ТОЛЬКО В 1 БЛОК
- find:
path: li:nth-of-type(1)
do:
- parse
# ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `anotherfield` ОБЪЕКТА `someobj`
- object_field_set:
object: someobj
field: anotherfield
# ПЕРЕЙДЕМ ПО ПУТИ КОТОРЫЙ ВЕДЕТ ДО НЕСКОЛЬКИХ БЛОКОВ,
# ЧТО БЫ ПО НИМ ПРОИТЕРИРОВАТЬ И ЗАПИСАТЬ ДАННЫЕ В ОБЪЕКТ `someobj`
- find:
path: .anotherpath
do:
# СОЗДАДИМ НОВЫЙ ОБЪЕКТ ДЛЯ ХРАНЕНИЯ ДАННЫХ ТЕКУЩЕГО БЛОКА
- object_new: anotherobj
# ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `anotherobj`
- parse
- object_field_set:
object: anotherobj
field: somefield
# СОХРАНИМ ОБЪЕКТ `anotherobj` В ОБЪЕКТ `someobj`
- object_save:
name: anotherobj
to: someobj
# СОХРАНИМ ОБЪЕКТ `someobj`
- object_save:
name: someobj
# ПРИВЕДЕМ ПРИМЕР КАК ДЕЛАТЬ НЕЛЬЗЯ :)
- find:
path: .somepath
do:
# СОЗДАЕМ ОБЪЕКТ С ИМЕНЕМ `someobj`
- object_new: someobj
# ЗАПОЛНЯЕМ РЕГИСТ ДАННЫМИ
- parse
# ЗАПИСЫВАЕМ ЗНАЧЕНИК РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `someobj`
- object_field_set:
object: someobj
field: somefield
# ПЕРЕЙДЕМ ПО ПУТИ КОТОРЫЙ ВЕДЕТ ДО НЕСКОЛЬКИХ БЛОКОВ,
# ЧТО БЫ ПО НИМ ПРОИТЕРИРОВАТЬ И ЗАПИСАТЬ ДАННЫЕ В ОБЪЕКТ `someobj`
- find:
path: .anotherpath
do:
# СОЗДАДИМ НОВЫЙ ОБЪЕКТ ДЛЯ ХРАНЕНИЯ ДАННЫХ ТЕКУЩЕГО БЛОКА
- object_new: anotherobj
# ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `anotherobj`
- parse
- object_field_set:
object: anotherobj
field: somefield
# СОХРАНИМ ОБЪЕКТ `anotherobj` В ОБЪЕКТ `someobj`
- object_save:
name: anotherobj
to: someobj
# ПЕРЕЙДЕМ В ДРУГОЙ БЛОК И ЗАПИШЕМ ЧТО НИБУДЬ В ДРУГОЕ ПОЛЕ ОБЪЕКТА `someobj`
- find:
path: li:nth-of-type(1)
do:
- parse
# ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `anotherfield` ОБЪЕКТА `someobj`
- object_field_set:
object: someobj
field: anotherfield
# А ТЕПЕРЬ, СОХРАНИМ ОБЪЕКТ `someobj` В ЭТОМ БЛОКЕ
- object_save:
name: someobj
# ПРОБЛЕМА ЗАКЛЮЧАЕТСЯ В ТОМ, ЧТО ЕСЛИ НЕ БУДЕТ НАЙДЕНО НИ ОДНОГО БЛОКА ПО ПУТИ `li:nth-of-type(1)`
# ОБЪЕКТ `someobj` НЕ БУДЕТ СОХРАНЕН, В ТАКОМ СЛУЧАЕ ВЫ ПОТЕРЯЕТЕ ВСЕ ДАННЫЕ ЗАПИСАННЫЕ В НЕГО ДО ЭТОГО МОМЕНТА.
# ЭТО НЕЯВНАЯ ОШИБКА И ДИГГЕР БУДЕТ РАБОТАТЬ ВПОЛНЕ КОРРЕКТНО С ТАКОЙ ЗАПИСЬЮ, НО В ДАННЫХ ВОЗМОЖНЫ ПРОБЛЕМЫ.
{
"someobj": {
"somefield" : "somedata",
"anotherfield": "anotherdata",
"anotherobj" : [
{
"somefield":"somedata"
},
{
"somefield":"somedata"
},
...
...
...
{
"somefield":"somedata"
},
{
"somefield":"somedata"
}
]
}
}
Запись поля в объект с указанием типа (поддерживаются типы int, float, bool, string). Если тип опущен используется стандатный тип string:
# СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul>
<li class="float">12.85</li>
<li class="int">158</li>
<li class="bool_false">false</li>
<li class="bool_true">true</li>
</ul>'
- to_block
- find:
path: ul
do:
# СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
- object_new: item
- find:
path: .float
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefloat` С УКАЗАНИЕМ ТИПА `float`
- object_field_set:
object: item
field: somefloat
type: float
- find:
path: .int
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `someint` С УКАЗАНИЕМ ТИПА `int`
- object_field_set:
object: item
field: someint
type: int
- find:
path: .bool_false
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `falsebool` С УКАЗАНИЕМ ТИПА `bool`
- object_field_set:
object: item
field: falsebool
type: bool
- find:
path: .bool_true
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `truebool` С УКАЗАНИЕМ ТИПА `bool`
- object_field_set:
object: item
field: truebool
type: bool
# ЗАПИШЕМ ОБЪЕКТ `item`
- object_save:
name: item
{
"item": {
"somefloat": 12.85,
"someint": 158,
"falsebool": false,
"truebool": true
}
}
Запись поля в объект с объединением значений:
# СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul class="int">
<li>125</li>
<li>158</li>
</ul>
<ul class="float">
<li>12.5</li>
<li>15.8</li>
</ul>
<ul class="default">
<li>sometext</li>
<li>15.8</li>
</ul>'
- to_block
- find:
path: ul.int
do:
# СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
- object_new: item
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `multint` С УКАЗАНИЕМ ТИПА `int`
- object_field_set:
object: item
field: multint
type: int
joinby: "*" # УМНОЖЕНИЕ
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `divint` С УКАЗАНИЕМ ТИПА `int`
- object_field_set:
object: item
field: divint
type: int
joinby: "/" # ДЕЛЕНИЕ
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `subint` С УКАЗАНИЕМ ТИПА `int`
- object_field_set:
object: item
field: subint
type: int
joinby: "-" # ВЫЧИТАНИЕ
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sumint` С УКАЗАНИЕМ ТИПА `int`
- object_field_set:
object: item
field: sumint
type: int
joinby: "+" # СЛОЖЕНИЕ
# СОХРАНИМ ОБЪЕКТ `item`
- object_save:
name: item
{
"item": {
"divint": 0,
"multint": 19750,
"subint": -33,
"sumint": 283
}
}
# СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul class="int">
<li>125</li>
<li>158</li>
</ul>
<ul class="float">
<li>12.5</li>
<li>15.8</li>
</ul>
<ul class="default">
<li>sometext</li>
<li>15.8</li>
</ul>'
- to_block
- find:
path: ul.float
do:
# СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
- object_new: item
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `multfloat` С УКАЗАНИЕМ ТИПА `float`
- object_field_set:
object: item
field: multfloat
type: float
joinby: "*" # УМНОЖЕНИЕ
precision: 2
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `divfloat` С УКАЗАНИЕМ ТИПА `float`
- object_field_set:
object: item
field: divfloat
type: float
joinby: "/" # ДЕЛЕНИЕ
precision: 3
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `subfloat` С УКАЗАНИЕМ ТИПА `float`
- object_field_set:
object: item
field: subfloat
type: float
joinby: "-" # ВЫЧИТАНИЕ
precision: 4
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sumfloat` С УКАЗАНИЕМ ТИПА `float`
- object_field_set:
object: item
field: sumfloat
type: float
joinby: "+" # СЛОЖЕНИЕ
precision: 5
# СОХРАНИМ ОБЪЕКТ `item`
- object_save:
name: item
{
"item": {
"divfloat": 0.7911392405063291,
"multfloat": 197.5,
"subfloat": -3.3000000000000007,
"sumfloat": 28.3
}
}
# СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul class="int">
<li>125</li>
<li>158</li>
</ul>
<ul class="float">
<li>12.5</li>
<li>15.8</li>
</ul>
<ul class="default">
<li>sometext</li>
<li>15.8</li>
</ul>'
- to_block
- find:
path: ul.default
do:
# СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
- object_new: item
- find:
path: li
do:
# ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
- parse
# ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `default` С УКАЗАНИЕМ РАЗДЕЛИТЕЛЯ
- object_field_set:
object: item
field: default
joinby: "*" # РАЗДЕЛИТЕЛЬ
# СОХРАНИМ ОБЪЕКТ `item`
- object_save:
name: item
{
"item": {
"default": "sometext*15.8"
}
}
Команды object_save и object_check поддерживают специальный режим апдейта. По умолчанию этот режим отключен и для его включения необходимо передать параметр mode со значением update, так, как показано в примере внизу. Вместе с параметром mode, вам нужно также передать параметр primary_key с именем поля вашего датасета, которое будет использоваться в качестве первичного (уникального) ключа записи. В этом режиме, система сравнивает контрольную сумму последней сохраненной записи с заданным ключем с контрольной суммой новой записи. Если суммы совпадают, запись не будет записана, так как система посчитает ее дубликатом уже когда-то собранной записи. В противном случае, новая запись будет сохранена и контрольная сумма для ключа в кэше будет обновлена до текущей.
# SAVE OBJECT `item`
- object_save:
name: item
mode: update
primary_key: title
В следующей главе мы рассмотрим методы для работы с DOM структурой документа.