Auto-associações no Azure Cosmos DB para NoSQL
APLICA-SE A: NoSQL
No Azure Cosmos DB para NoSQL, os dados são livres de esquema e normalmente desnormalizados. Em vez de unir dados entre entidades e conjuntos, como faria em um banco de dados relacional, as junções ocorrem dentro de um único item. Especificamente, as junções têm escopo para esse item e não podem ocorrer em vários itens e contêineres.
Gorjeta
Se você precisar unir itens e contêineres, considere retrabalhar seu modelo de dados para evitar isso.
Auto-associação com um único item
Vejamos um exemplo de uma auto-junção dentro de um item. Considere um recipiente com um único item. Este item representa um produto com várias tags:
[
{
"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 deste produto? Normalmente, você precisaria escrever uma consulta que tenha um filtro verificando cada índice potencial na matriz em busca de um valor com um prefixo tags
de 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-")
Esta técnica pode tornar-se insustentável rapidamente. A complexidade ou o comprimento da sintaxe de 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 podem ter mais de três tags.
Em um banco de dados relacional tradicional, as tags seriam separadas em uma tabela separada e uma junção entre tabelas é realizada com um filtro aplicado aos resultados. Na API para NoSQL, podemos executar uma operação de auto-junção dentro do item usando a JOIN
palavra-chave.
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 tags.
[
{
"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 detalhar a consulta. A consulta agora tem dois aliases: p
para cada item de produto no conjunto de resultados e t
para a matriz autoassociada tags
. A *
palavra-chave só é válida para projetar todos os campos se puder inferir o conjunto de entradas, mas agora há dois conjuntos de entrada (p
e t
). Devido a essa restrição, devemos definir explicitamente nossos campos retornados como id
e sku
do produto junto com slug
as tags . Para tornar essa consulta mais fácil de ler e entender, podemos soltar o id
campo e usar um alias para o campo da name
tag para renomeá-lo para 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"
}
]
Finalmente, podemos usar um filtro para encontrar a tag color-group-purple
. Como usamos a JOIN
palavra-chave, nosso filtro é flexível o suficiente para lidar com qualquer número variável de tags.
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"
}
]
Auto-junção de vários itens
Vamos passar para um exemplo onde 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 tags relevantes para esse item.
[
{
"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 com um formato de saco de múmia ? Você poderia pesquisar a tag bag-shape-mummy
, mas precisaria escrever uma consulta complexa que levasse em conta duas características desses itens:
A tag com um
bag-shape-
prefixo ocorre em índices diferentes em cada matriz. Para o saco de dormir Varetino , a etiqueta é o terceiro item (índice:2
). Para o saco de dormir Maresse , a etiqueta é o primeiro item (índice:0
).A
tags
matriz para cada item tem um comprimento diferente. O saco de dormir Vareno tem duas etiquetas, enquanto o saco de dormir Maresse tem três.
Aqui, a JOIN
palavra-chave é uma ótima ferramenta para criar um produto cruzado dos itens e tags. As junções criam um produto cruzado completo dos conjuntos que participam na 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 em nossos produtos e tags de saco de dormir de amostra cria os seguintes itens:
Item | Etiqueta |
---|---|
Saco de dormir Maresse (6') Ming | Forma do saco: Múmia |
Saco de dormir Maresse (6') Ming | Isolamento do saco: Down Fill |
Vareno Saco de dormir (6') Cúrcuma | Isolamento do saco: Enchimento sintético |
Vareno Saco de dormir (6') Cúrcuma | Grupo de cores: Amarelo |
Vareno Saco de dormir (6') Cúrcuma | Forma do saco: Múmia |
Aqui está 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 com o item único, você pode aplicar um filtro aqui para encontrar apenas itens que correspondam a uma tag específica. Por exemplo, essa consulta localiza todos os itens com uma tag nomeada bag-shape-mummy
para atender ao requisito inicial mencionado anteriormente 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 tag 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"
}
]