Autojunção no Azure Cosmos DB for NoSQL
APLICA-SE A: NoSQL
No Azure Cosmos DB for NoSQL, os dados são livres de esquema e normalmente desnormalizados. Em vez de unir dados entre entidades e conjuntos, como você faria em um banco de dados relacional, as junções ocorrem em um só item. Especificamente, as junções têm como escopo esse item e não podem ocorrer em vários itens e contêineres.
Dica
Se você precisar ingressar em itens e contêineres, considere reformular o modelo de dados para evitar isso.
Autojunção com um só item
Vamos examinar um exemplo de uma autojunção dentro de um item. Considere um contêiner com um só item. Este item representa um produto com várias marcas:
[
{
"id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"categoryId": "bbbbbbbb-1111-2222-3333-cccccccccccc",
"name": "Teapo Surfboard (6'10\") Grape",
"sku": "teapo-surfboard-72109",
"tags": [
{
"id": "cccccccc-2222-3333-4444-dddddddddddd",
"slug": "tail-shape-swallow",
"name": "Tail Shape: Swallow"
},
{
"id": "dddddddd-3333-4444-5555-eeeeeeeeeeee",
"slug": "length-inches-82",
"name": "Length: 82 inches"
},
{
"id": "eeeeeeee-4444-5555-6666-ffffffffffff",
"slug": "color-group-purple",
"name": "Color Group: Purple"
}
]
}
]
E se você precisar encontrar o grupo de cores desse produto? Normalmente, você precisaria escrever uma consulta com um filtro verificando cada índice possível na matriz tags
para obter um valor com o prefixo color-group-
.
SELECT
*
FROM
products p
WHERE
STARTSWITH(p.tags[0].slug, "color-group-") OR
STARTSWITH(p.tags[1].slug, "color-group-") OR
STARTSWITH(p.tags[2].slug, "color-group-")
Essa técnica pode se tornar insustentável rapidamente. A complexidade ou comprimento da sintaxe da consulta aumenta o número de itens potenciais na matriz. Além disso, essa consulta não é flexível o suficiente para lidar com produtos futuros que possam ter mais de três marcas.
Em um banco de dados relacional tradicional, as marcas seriam separadas em uma tabela separada e uma junção entre tabelas seria executada com um filtro aplicado aos resultados. Na API para NoSQL, podemos executar uma operação de autojunção dentro do item usando a palavra-chave JOIN
.
SELECT
p.id,
p.sku,
t.slug
FROM
products p
JOIN
t IN p.tags
Essa consulta retorna uma matriz simples com um item para cada valor na matriz de marcas.
[
{
"id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"sku": "teapo-surfboard-72109",
"slug": "tail-shape-swallow"
},
{
"id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"sku": "teapo-surfboard-72109",
"slug": "length-inches-82"
},
{
"id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"sku": "teapo-surfboard-72109",
"slug": "color-group-purple"
}
]
Vamos dividir a consulta. A consulta agora tem dois aliases: p
para cada item de produto no conjunto de resultados e t
para a matriz com autojunção tags
. A palavra-chave *
só será válida para projetar todos os campos se puder inferir o conjunto de entrada, mas agora há dois conjuntos de entrada (p
e t
). Devido a essa restrição, precisamos definir explicitamente os campos retornados como id
e sku
do produto, juntamente com slug
das marcas. Para facilitar a leitura e a compreensão dessa consulta, podemos remover o campo id
e usar um alias para o campo da marca name
a fim de renomeá-lo como tag
.
SELECT
p.sku,
t.name AS tag
FROM
products p
JOIN
t IN p.tags
[
{
"sku": "teapo-surfboard-72109",
"tag": "Tail Shape: Swallow"
},
{
"sku": "teapo-surfboard-72109",
"tag": "Length: 82 inches"
},
{
"sku": "teapo-surfboard-72109",
"tag": "Color Group: Purple"
}
]
Por fim, podemos usar um filtro para localizar a marca color-group-purple
. Como usamos a palavra-chave JOIN
, o filtro é flexível o suficiente para lidar com qualquer número variável de marcas.
SELECT
p.sku,
t.name AS tag
FROM
products p
JOIN
t IN p.tags
WHERE
STARTSWITH(t.slug, "color-group-")
[
{
"sku": "teapo-surfboard-72109",
"tag": "Color Group: Purple"
}
]
Autojunção de vários itens
Vamos passar para um exemplo em que precisamos encontrar um valor dentro de uma matriz que existe em vários itens. Para este exemplo, considere um contêiner com dois itens de produto. Cada item contém marcas relevantes para ele.
[
{
"id": "ffffffff-5555-6666-7777-aaaaaaaaaaaa",
"categoryId": "cccccccc-8888-9999-0000-dddddddddddd",
"categoryName": "Sleeping Bags",
"name": "Maresse Sleeping Bag (6') Ming",
"sku": "maresse-sleeping-bag-65503",
"tags": [
{
"id": "b1b1b1b1-cccc-dddd-eeee-f2f2f2f2f2f2",
"slug": "bag-shape-mummy",
"name": "Bag Shape: Mummy"
},
{
"id": "bbbbbbbb-7777-8888-9999-cccccccccccc",
"slug": "bag-insulation-down-fill",
"name": "Bag Insulation: Down Fill"
}
]
},
{
"id": "c2c2c2c2-dddd-eeee-ffff-a3a3a3a3a3a3",
"categoryId": "cccccccc-8888-9999-0000-dddddddddddd",
"categoryName": "Sleeping Bags",
"name": "Vareno Sleeping Bag (6') Turmeric",
"sku": "vareno-sleeping-bag-65508",
"tags": [
{
"id": "dddddddd-9999-0000-1111-eeeeeeeeeeee",
"slug": "bag-insulation-synthetic-fill",
"name": "Bag Insulation: Synthetic Fill"
},
{
"id": "a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1",
"slug": "color-group-yellow",
"name": "Color Group: Yellow"
},
{
"id": "b1b1b1b1-cccc-dddd-eeee-f2f2f2f2f2f2",
"slug": "bag-shape-mummy",
"name": "Bag Shape: Mummy"
}
]
}
]
E se você precisasse encontrar todos os itens que tivessem o formato de sacola (bag shape) mummy? Você poderia procurar a marca bag-shape-mummy
, mas precisaria escrever uma consulta complexa considerando duas características desses itens:
A marca com um prefixo
bag-shape-
ocorre em diferentes índices em cada matriz. Para o saco de dormir (sleeping bag) Vareno, a marca é o terceiro item (índice:2
). Para o saco de dormir Maresse, a marca é o terceiro item (índice:0
).A matriz
tags
de cada item tem um comprimento diferente. O saco de dormir Vareno tem duas marcas, enquanto o saco de dormir Maresse tem três.
Aqui, a palavra-chave JOIN
é uma ótima ferramenta para criar um produto cruzado de itens e marcas. As junções criam um produto cruzado completo dos conjuntos que participam da junção. O resultado é um conjunto de tuplas com cada permutação do item e os valores dentro da matriz de destino.
Uma operação de junção nos produtos e nas marcas de saco de dormir de exemplo cria os seguintes itens:
Item | Marca |
---|---|
Maresse Sleeping Bag (6') Ming | Bag Shape: Mummy |
Maresse Sleeping Bag (6') Ming | Bag Insulation: Down Fill |
Vareno Sleeping Bag (6') Turmeric | Bag Insulation: Synthetic Fill |
Vareno Sleeping Bag (6') Turmeric | Color Group: Yellow |
Vareno Sleeping Bag (6') Turmeric | Bag Shape: Mummy |
Veja a consulta SQL e o conjunto de resultados JSON para uma junção que inclui vários itens no contêiner.
SELECT
p.sku,
t.name AS tag
FROM
products p
JOIN
t IN p.tags
WHERE
p.categoryName = "Sleeping Bags"
[
{
"sku": "maresse-sleeping-bag-65503",
"tag": "Bag Shape: Mummy"
},
{
"sku": "maresse-sleeping-bag-65503",
"tag": "Bag Insulation: Down Fill"
},
{
"sku": "vareno-sleeping-bag-65508",
"tag": "Bag Insulation: Synthetic Fill"
},
{
"sku": "vareno-sleeping-bag-65508",
"tag": "Color Group: Yellow"
},
{
"sku": "vareno-sleeping-bag-65508",
"tag": "Bag Shape: Mummy"
}
]
Assim como acontece com o único item, você pode aplicar um filtro aqui para localizar apenas itens que correspondam a uma marca específica. Por exemplo, essa consulta localiza todos os itens com uma marca chamada bag-shape-mummy
para atender ao requisito inicial já mencionado nesta seção.
SELECT
p.sku,
t.name AS tag
FROM
products p
JOIN
t IN p.tags
WHERE
p.categoryName = "Sleeping Bags" AND
t.slug = "bag-shape-mummy"
[
{
"sku": "maresse-sleeping-bag-65503",
"tag": "Bag Shape: Mummy"
},
{
"sku": "vareno-sleeping-bag-65508",
"tag": "Bag Shape: Mummy"
}
]
Você também pode alterar o filtro para obter um conjunto de resultados diferente. Por exemplo, essa consulta localiza todos os itens que têm uma marca chamada bag-insulation-synthetic-fill
.
SELECT
p.sku,
t.name AS tag
FROM
products p
JOIN
t IN p.tags
WHERE
p.categoryName = "Sleeping Bags" AND
t.slug = "bag-insulation-synthetic-fill"
[
{
"sku": "vareno-sleeping-bag-65508",
"tag": "Bag Insulation: Synthetic Fill"
}
]