Выборка данных из массивов
Reindexer поддерживает следующие виды выборки данных из массивов:
- выборка с условиями,
- выборка данных с использованием агрегатных функций,
- выборка с условиями для элементов с одинаковыми индексами,
- выборка с условиями для элементов с одинаковыми индексами с учетом группировки.
Выборка с условиями из полей-массивов
Reindexer поддерживает выборку из полей-массивов со следующими операторами сравнения (условиями фильтрации): <, >, =, IN, IS NULL, ALLSET.
Подробнее об операторах сравнения для SQL и Go в Reindexer — в разделе «Выборка данных с условиями».
Запросы с условиями фильтрации <, > и = возвращают записи, в которых в поле-массиве найден хотя бы один элемент, соответствующий условию. Примеры запросов:
db.Query("test_namespace")
.Where("array_field", reindexer.GT, 5)
SELECT * FROM test_namespace WHERE array_field > 5
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw \
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "array_field",
"cond": "GT",
"value": [
5
]
}
]
}
'
Запросы с условием фильтрации IN (SET) возвращают записи, в которых найдено любое из заданных в условии значений.
Примеры запросов:
db.Query("test_namespace")
.WhereInt("array_field", reindexer.SET, 5, 6, 9)
SELECT * FROM test_namespace WHERE array_field IN (5, 6, 9)
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw \
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "array_field",
"cond": "SET",
"value": [
5,
6,
9
]
}
]
}
'
Условие фильтрации EMPTY(IS NULL) используется для поиска пустых массивов и null-значений (для sparse-индексов вместо поля-массива допустим null, и такой документ тоже будет найден по IS NULL, как и в случае со скалярными индексами).
db.Query("test_namespace")
.WhereInt("array_field", reindexer.EMPTY)
SELECT * FROM test_namespace WHERE array_field IS NULL
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "array_field",
"cond": "EMPTY"
}
]
}
'
Запросы с условием фильтрации ALLSET возвращают записи, в которых в поле-массиве найдены все из заданных в условии значений.
db.Query("test_namespace")
.WhereInt("array_field", reindexer.ALLSET, 1, 2, 3)
SELECT * FROM test_namespace WHERE array_field ALLSET (1, 2, 3)
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "array_field",
"cond": "ALLSET",
"value": [
1,
2,
3
]
}
]
}
'
Также запросы с условием фильтрации ALLSET могут использоваться для поиска вхождений одного поля-массива в другое. Примеры:
db.Query("test_namespace")
.WhereBetweenFields("array_field1", reindexer.ALLSET, "array_field2")
SELECT * FROM test_namespace WHERE array_field1 ALLSET array_field2
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"first_field": "array_field1",
"cond": "ALLSET",
"second_field": "array_field2"
}
]
}
'
Выборка данных с использованием агрегатных функций
Reindexer поддерживает выборку из полей-массивов c использованием следующих агрегатных функций: SUM, AVG, MIN, MAX, COUNT, FACET.
Подробнее об агрегатных функциях для SQL и Go в Reindexer — в разделе «Агрегатные функции».
Запросы с агрегатной функцией SUM могут использоваться для:
- вычисления суммы элементов всех полей-массивов с указанным в запросе именем из всех записей неймспейса. Пример:
query := db.Query("test_namespace")
query.AggregateSum("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggSumRes := iterator.AggResults()[0]
if aggSumRes.Value != nil {
fmt.Printf("Сумма всех элементов полей-массивов 'array_field' всех записей неймспейса = %v\n", *aggSumRes.Value)
} else {
fmt.Println("Нет данных для агрегации")
}
SELECT SUM (array_field) FROM test_namespace
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [
"array_field"
],
"type": "SUM"
}
]
}
'
- вычисления суммы элементов определенного поля-массива записи, указанной в условии. Пример:
query := db.Query("test_namespace")
.Where("id", reindexer.EQ, 0)
query.AggregateSum("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggSumRes := iterator.AggResults()[0]
if aggSumRes.Value != nil {
fmt.Printf("Сумма элементов поля-массива 'array_field' для записи неймспейса с заданным `id` = %v\n", *aggSumRes.Value)
} else {
fmt.Println("Нет данных для агрегации")
}
SELECT SUM(array_field) FROM test_namespace WHERE id = 0
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [
"array_field"
],
"type": "SUM"
}
],
"filters": [
{
"field": "id",
"cond": "EQ",
"value": [
0
]
}
]
}
'
Запросы с агрегатной функцией AVG могут использоваться для:
- вычисления среднего значения элемента всех полей-массивов с указанным в запросе именем из всех записей неймспейса. Пример:
query := db.Query("test_namespace")
query.AggregateAvg("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggAvgRes := iterator.AggResults()[0]
if aggAvgRes.Value != nil {
fmt.Printf("Среднее значение элемента поля-массива 'array_field' для всех записей неймспейса `id` = %v\n", *aggAvgRes.Value)
} else {
fmt.Println("Нет данных для агрегации")
}
SELECT AVG(array_field) FROM test_namespace
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [
"array_field"
],
"type": "AVG"
}
]
}
'
- вычисления среднего значения элемента определенного поля-массива записи, указанной в условии. Пример:
query := db.Query("test_namespace")
.Where("id", reindexer.EQ, 0)
query.AggregateAvg("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggAvgRes := iterator.AggResults()[0]
if aggAvgRes.Value != nil {
fmt.Printf("Среднее значение элемента поля-массива 'array_field' для записи неймспейса с заданным `id` = %v\n", *aggAvgRes.Value)
} else {
fmt.Println("Нет данных для агрегации")
}
SELECT AVG(array_field) FROM test_namespace WHERE id = 0
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [
"array_field"
],
"type": "AVG"
}
],
"filters": [
{
"field": "id",
"cond": "EQ",
"value": [
0
]
}
]
}
'
Запросы с агрегатными функциями MIN/MAX могут использоваться для:
- поиска минимального/максимального значения элемента во всех полях-массива с указанным в запросе именем из всех записей неймспейса. Пример:
query := db.Query("test_namespace")
query.AggregateMin("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggMinRes := iterator.AggResults()[0]
if aggMinRes.Value != nil {
fmt.Printf("Минимальное значение элемента для полей-массивов 'array_field' всех записей неймспейса = %v\n", *aggSumRes.Value)
} else {
fmt.Println("Нет данных для агрегации")
}
SELECT MIN(array_field) FROM test_namespace
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [
"array_field"
],
"type": "MIN"
}
]
}
'
- поиска минимального/максимального значения элемента определенного поля-массива записи, указанной в условии. Пример:
query := db.Query("test_namespace")
.Where("id", reindexer.EQ, 0)
query.AggregateMin("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggMinRes := iterator.AggResults()[0]
if aggMinRes.Value != nil {
fmt.Printf("Минимальное значение элемента поля-массива 'array_field' для записи неймспейса с заданным `id` = %v\n", *aggMinRes.Value)
} else {
fmt.Println("Нет данных для агрегации")
}
SELECT MIN(array_field) FROM test_namespace WHERE id = 0
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [
"array_field"
],
"type": "MIN"
}
],
"filters": [
{
"field": "id",
"cond": "EQ",
"value": [
0
]
}
]
}
'
Агрегатная функция FACET используется для получения уникальных значений полей-массивов в записях неймспейса и подсчета их количества.
Фасет формируется по значениям элементов в массивах, а не по самим уникальным массивам.
Например, если в неймспейсе есть 3 записи с полем-массивом array_field:
Запись 1:
{
"id": 0,
"array_field": [1, 2]
}
Запись 2:
{
"id": 1,
"array_field": [1, 3]
}
Запись 3:
{
"id": 2,
"array_field": [1, 4]
}
то выдача по запросу SELECT FACET(array_field) FROM test_namespace будет выглядеть следующим образом:
count |
array_field |
|---|---|
| 3 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
В этом примере количество уникальных значений элементов полей-массивов будет равно 4 (уникальные значения: 1, 2, 3, 4). Количество самих значений в полях-массивах суммарно во всех записях указано в поле count.
Примеры запросов:
query := db.Query("test_namespace")
query.AggregateFacet("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggFacet := iterator.AggResults()[0]
fmt.Printf("'Значение поля массива' -> Кол. уникальных\n")
for _, facet := range aggFacet.Facets {
fmt.Printf("'%v' -> %v\n", facet.Values[0], facet.Count)
}
SELECT FACET(array_field) FROM test_namespace
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [
"array_field"
],
"type": "FACET"
}
]
}
'
Агрегатная функция FACET может использоваться совместно с операторами сравнения (подробнее о них — в разделе «Выборка данных с условиями»). Примеры:
query := db.Query("test_namespace")
.WhereInt("id", reindexer.GT, 5)
query.AggregateFacet("array_field")
iterator := query.Exec()
if err := iterator.Error(); err != nil {
panic(err)
}
defer iterator.Close()
aggFacet := iterator.AggResults()[0]
fmt.Printf("'Значение поля массива' -> Кол. уникальных\n")
for _, facet := range aggFacet.Facets {
fmt.Printf("'%v' -> %v\n", facet.Values[0], facet.Count)
}
SELECT FACET(array_field) FROM test_namespace WHERE id > 5
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"aggregations": [
{
"fields": [],
"type": "FACET"
}
],
"filters": [
{
"field": "array_field",
"cond": "GT",
"value": [
5
]
}
]
}
'
Выборка элементов с одинаковыми индексами из полей-массивов
В Reindexer есть возможность добавить дополнительное условие к фильтрам по полям-массивам, требующее, чтобы индексы элементов массивов, удовлетворяющих фильтрам, совпадали для указанных в условии полей.
Для этого используется функция EQUAL_POSITION().
Например, есть массив структур:
type Elem struct {
Price int `reindex:"array_field1"`
Discount int `reindex:"array_field2"`
}
type Payment struct {
Elems []Elem
}
В случае простой выборки запрос будет выглядеть следующим образом:
db.Query("test_namespace")
.Where("array_field1", reindexer.EQ, 1)
.Where("array_field2", reindexer.EQ, 2)
SELECT * FROM test_namespace WHERE array_field1 = 1 AND array_field2 = 2
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "array_field1",
"cond": "EQ",
"value": [
1
]
},
{
"field": "array_field2",
"cond": "EQ",
"value": [
2
]
},
]
}
'
Этот запрос вернет все записи, в которых в поле array_field1 найдется значение 1, а в поле array_field2 найдется значение 2.
Например, если в таблице будет 2 записи:
{
"id": 0,
"array_field1": [1, 2, 7],
"array_field2": [1, 2, 5]
}
и
{
"id": 1,
"array_field1": [1, 2, 7],
"array_field2": [2, 1, 5]
}
запрос вернет их обе.
Запрос с EQUAL_POSITION будет выглядеть следующим образом:
db.Query("test_namespace")
.Where("array_field1", reindexer.EQ, 1)
.Where("array_field2", reindexer.EQ, 2)
.EqualPosition("array_field1", "array_field2")
SELECT * FROM test_namespace WHERE array_field1 = 1 AND array_field2 = 2 EQUAL_POSITION(array_field1, array_field2)
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "array_field1",
"cond": "EQ",
"value": [
1
]
},
{
"field": "array_field2",
"cond": "EQ",
"value": [
2
]
},
{
"equal_positions": [
{
"positions": [
"array_field1",
"array_field2"
]
}
]
}
]
}
'
Этот запрос вернет все записи, в которых в поле array_field1 найдется значение 1, а в поле array_field2 найдется значение 2 и индексы найденных значений в массивах совпадут.
Например, если в таблице будет 2 записи:
{
"id": 0,
"array_field1": [1, 2, 7],
"array_field2": [1, 2, 5]
}
и
{
"id": 1,
"array_field1": [1, 2, 7],
"array_field2": [2, 1, 5]
}
запрос вернет только вторую запись:
{
"id": 1,
"array_field1": [1, 2, 7],
"array_field2": [2, 1, 5]
}
т. к. в первой для заданных в запросе значений не совпадают индексы в массивах: значение array_field1 = 1 найдено на нулевой позиции в массиве [1, 2 ,7], значение array_field2 = 2 найдено на первой позиции в массиве [1, 2, 5].
В EQUAL_POSITION можно передавать не менее 2 полей и не более, чем полей в условии.
Использование EQUAL_POSITION в сложных выражениях
Функция EQUAL_POSITION() может использоваться в сложных выражениях.
При этом она должна находиться внутри скобок, т.к. применяется к полям внутри скобок.
При использовании функции EQUAL_POSITION() в сложных выражениях вне скобок возможно неопределенное поведение.
Примеры:
EQUAL_POSITION() применяется к полям внутри скобок:
SELECT
*
FROM
test_namespace
WHERE
(
array_field1 >= 5
AND array_field2 = 100
EQUAL_POSITION(array_field1, array_field2)
)
OR
(
array_field3 = 3
AND array_field4 < 4
AND array_field5 = 7
EQUAL_POSITION(array_field3, array_field4, array_field5)
)
EQUAL_POSITION() применяется к полям внутри скобок:
SELECT
*
FROM
test_namespace
WHERE
(
array_field1 >= 5
AND array_field2 = 100
AND array_field3 = 3
AND array_field4 < 4
EQUAL_POSITION(array_field1, array_field3)
EQUAL_POSITION(array_field2, array_field4)
)
OR
(
array_field5 = 3
AND array_field6 < 4
AND array_field7 = 7
EQUAL_POSITION(array_field5, array_field7)
)
SELECT
*
FROM
test_namespace
WHERE
array_field1 >= 5
AND
(
array_field2 = 100
AND array_field3 = 3
AND array_field4 < 4
EQUAL_POSITION(array_field2, array_field3)
)
AND array_field5 = 3
AND array_field6 < 4
EQUAL_POSITION(array_field1, array_field5, array_field6)
Ограничения EQUAL_POSITION
В Reindexer функция EQUAL_POSITION() не работает в запросах со следующими условиями:
IS NULL,IS EMPTY,IN()с пустым списком значений.
В условиях и EQUAL_POSITION() можно передавать как имена индексов, так и JSON-пути.
Для поля в условии и EQUAL_POSITION возможны следующие комбинации:
-
индекс (
name), построенный поверх одного JSON-пути (json_paths1):Условие EQUAL_POSITIONДопустимо namename+ namejson_paths1+ json_paths1json_paths1+ json_paths1name+ -
индекс (
name), построенный поверх нескольких JSON-путей (json_paths1,json_paths2):Условие EQUAL_POSITIONДопустимо namename+ namejson_paths1+ namejson_paths2+ json_paths1json_paths1+ json_paths1json_paths2- json_paths2json_paths1- json_paths2json_paths2+ json_paths1name- json_paths1name-
Выборка элементов с одинаковыми индексами с учетом группировки
Для вложенных массивов поддерживается логика группировки.
Для этого после имени поля надо поставить метку [#]. Она должна присутствовать
в каждом поле, переданном в EQUAL_POSITION, причём только одна.
В этом случае при обработке EQUAL_POSITION() будет сформирована таблица. Каждая строка содержит все значения
по одному индексу помеченного массива, а номер строки равен этому индексу.
Примеры выборки с группировкой
Пусть есть структура:
type Filters struct {
ID int `reindex:"id,,pk"`
Filters []Element `reindex:"filters"`
}
type Element struct {
Price int64 `reindex:"price"`
Discounts []int64 `reindex:"discount"`
}
и запись:
{
"ID": 1,
"Filters": [
{
"Price": 99,
"Discounts": [
1,
2
]
},
{
"Price": 87,
"Discounts": [
1
]
}
]
}
Пример 1:
Если требуется найти все документы, у которых в массиве Filters есть хотя бы один объект, удовлетворяющий условиям, запрос будет выглядеть следующим образом:
db.Query("test_namespace").
Where("Filters.Price", reindexer.EQ, 87).
Where("Filters.Discounts", reindexer.EQ, 1).
EqualPosition("Filters[#].Price", "Filters[#].Discounts")
SELECT * FROM test_namespace WHERE Filters.Price = 87 AND Filters.Discounts = 1 EQUAL_POSITION(Filters[#].Price, Filters[#].Discounts)
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "Filters.Price",
"cond": "EQ",
"value": [
87
]
},
{
"field": "Filters.Discounts",
"cond": "EQ",
"value": [
1
]
},
{
"equal_positions": [
{
"positions": [
"Filters[#].Price",
"Filters[#].Discounts"
]
}
]
}
]
}
'
Промежуточная таблица для Filters[#].Price будет такой:
| N | |
|---|---|
| 0 | 99 |
| 1 | 87 |
Промежуточная таблица для Filters[#].Discounts будет такой:
| N | ||
|---|---|---|
| 0 | 1 |
2 |
| 1 | 1 |
Условия выполняются для строки 2 обеих таблиц, и запрос возвращает всю запись.
Пример 2:
Рассмотрим случай, когда Filters.Discounts должно быть равно 2:
db.Query("test_namespace").
Where("Filters.Price", reindexer.EQ, 87).
Where("Filters.Discounts", reindexer.EQ, 2).
EqualPosition("Filters[#].Price", "Filters[#].Discounts")
SELECT
*
FROM
test_namespace
WHERE
Filters.Price = 87
AND Filters.Discounts = 2
EQUAL_POSITION(Filters[#].Price, Filters[#].Discounts)
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "Filters.Price",
"cond": "EQ",
"value": [
87
]
},
{
"field": "Filters.Discounts",
"cond": "EQ",
"value": [
2
]
},
{
"equal_positions": [
{
"positions": [
"Filters[#].Price",
"Filters[#].Discounts"
]
}
]
}
]
}
'
Промежуточная таблица для Filters[#].Price:
| N | |
|---|---|
| 0 | 99 |
| 1 | 87 |
Промежуточная таблица для Filters[#].Discounts:
| N | ||
|---|---|---|
| 0 | 1 |
2 |
| 1 | 1 |
Условия выполняются на разных строках таблиц, запрос не возвращает записей.
Пример 3:
Пусть теперь Filters.Price должно быть равно 99:
db.Query("test_namespace").
Where("Filters.Price", reindexer.EQ, 99).
Where("Filters.Discounts", reindexer.EQ, 2).
EqualPosition("Filters[#].Price", "Filters[#].Discounts")
SELECT * FROM test_namespace WHERE Filters.Price = 99 AND Filters.Discounts = 2 EQUAL_POSITION(Filters[#].Price, Filters[#].Discounts)
curl \
--location \
--request POST \
http://127.0.0.1:9088/api/v1/db/testdb/query \
--header 'Content-Type: application/json' \
--data-raw
'
{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "Filters.Price",
"cond": "EQ",
"value": [
99
]
},
{
"field": "Filters.Discounts",
"cond": "EQ",
"value": [
2
]
},
{
"equal_positions": [
{
"positions": [
"Filters[#].Price",
"Filters[#].Discounts"
]
}
]
}
]
}
'
Промежуточная таблица для Filters[#].Price:
| N | |
|---|---|
| 0 | 99 |
| 1 | 87 |
Промежуточная таблица для Filters[#].Discounts:
| N | ||
|---|---|---|
| 0 | 1 |
2 |
| 1 | 1 |
Условия выполняются для строки 1 обеих таблиц и запрос возвращает запись.
Примеры сложных случаев группировки
Рассмотрим запись:
{
"array": [
{
"nested_object": {
"nested_array": [
{
"field": 1
},
{
"field": [5, 3]
}
]
}
},
{},
{
"nested_object": {
"nested_array": [
{
"field": null
},
{
"field": [4, 7]
}
]
}
}
]
}
Группировка array.nested_object.nested_array.field[#] последовательно
помещает все элементы массивов в полях field на строку, соответсвующую их
номеру, включая скаляры 1 и null:
| N | ||||
|---|---|---|---|---|
| 0 | 1 | 5 | null |
4 |
| 1 | 3 | 7 |
Группировка array.nested_object.nested_array[#].field заполняет строки
таблицы всеми значениями внутри элементов массива nested_array:
| N | ||||
|---|---|---|---|---|
| 0 | 1 | null |
||
| 1 | 5 | 3 | 4 | 7 |
Группировка array.nested_object[#].nested_array.field помещает все значения
на нулевую строку, т. к. оба объекта nested_object по одному индексу:
| N | ||||||
|---|---|---|---|---|---|---|
| 0 | 1 | 5 | 3 | null |
4 | 7 |
Группировка array[#].nested_object.nested_array.field действует следующим
образом:
| N | |||
|---|---|---|---|
| 0 | 1 | 5 | 3 |
| 1 | |||
| 2 | null |
4 | 7 |
Важно
Обратите внимание, что метка [#] может быть помещена только после
названия поля, т. е. для примера ниже группировка по индексам вложенных
массивов ([3, 4], [4, 7]) не поддерживается:
{
"array": [
{
"field": [
5,
[3, 4]
]
},
{
"field": [
1,
[4, 7]
]
}
]
}