Autocombinaciones en Azure Cosmos DB for NoSQL
SE APLICA A: NoSQL
En Azure Cosmos DB for NoSQL, los datos no tienen esquema y normalmente se desnormalizan. En lugar de combinar datos entre entidades y conjuntos, como lo haría en una base de datos relacional, las combinaciones se producen dentro de un solo elemento. En concreto, las combinaciones se limitan a ese elemento y no se pueden producir en varios elementos y contenedores.
Sugerencia
Si necesita unirse a elementos y contenedores, considere la posibilidad de volver a trabajar el modelo de datos para evitarlo.
Autocombinación con un solo elemento
Veamos un ejemplo de autocombinación dentro de un elemento. Considere un contenedor con un solo elemento. Este elemento representa un producto con varias etiquetas:
[
{
"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"
}
]
}
]
¿Qué ocurre si necesita encontrar el grupo de colores de este producto? Normalmente, tendría que escribir una consulta que tenga un filtro que comprueba cada índice potencial de la matriz tags
para un valor con un prefijo 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 puede volverse insostenible rápidamente. La complejidad o la longitud de la sintaxis de consulta aumenta el número de posibles elementos de la matriz. Además, esta consulta no es lo suficientemente flexible como para controlar los productos futuros, que pueden tener más de tres etiquetas.
En una base de datos relacional tradicional, las etiquetas se separarían en una tabla independiente y se realiza una combinación entre tablas con un filtro aplicado a los resultados. En la API para NoSQL, podemos realizar una operación de autocombinación dentro del elemento mediante la palabra clave JOIN
.
SELECT
p.id,
p.sku,
t.slug
FROM
products p
JOIN
t IN p.tags
Esta consulta devuelve una simple matriz con un elemento para cada valor de la matriz de etiquetas.
[
{
"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 a desglosar la consulta. La consulta ahora tiene dos alias: p
para cada elemento de producto del conjunto de resultados y t
para la matriz de autocombinación tags
. La palabra clave *
solo es válida para proyectar todos los campos si puede deducir el conjunto de entrada, pero ahora hay dos conjuntos de entrada (p
y t
). Debido a esta restricción, debemos definir explícitamente los campos devueltos como id
y sku
desde el producto junto con slug
desde las etiquetas. Para facilitar la lectura y comprensión de esta consulta, podemos quitar el campo id
y usar un alias para el campo de la etiqueta name
para cambiar su nombre a 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 último, podemos usar un filtro para buscar la etiqueta color-group-purple
. Dado que hemos usado la palabra clave JOIN
, nuestro filtro es lo suficientemente flexible como para administrar cualquier número variable de etiquetas.
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"
}
]
Autocombinación de varios elementos
Vamos a pasar a un ejemplo en el que necesitamos encontrar un valor dentro de una matriz que existe en varios elementos. En este ejemplo, considere un contenedor con dos elementos de producto. Cada elemento contiene etiquetas relevantes para ese elemento.
[
{
"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"
}
]
}
]
¿Qué ocurre si necesitaras encontrar cada artículo con forma de saco de momia? Podría buscar la etiqueta bag-shape-mummy
, pero tendría que escribir una consulta compleja que tenga en cuenta dos características de estos elementos:
La etiqueta con el prefijo
bag-shape-
aparece en distintos índices en las matrices. Para saco de dormir Vareno, la etiqueta es el tercer elemento (índice:2
). Para el saco de dormir Maresse, la etiqueta es el primer elemento (índice:0
).Cada elemento tiene una matriz
tags
de una longitud diferente. El saco de dormir Vareno tiene dos etiquetas mientras que el saco de dormir Maresse tiene tres.
Aquí, la palabra clave JOIN
es una excelente herramienta para crear un producto cruzado de elementos y etiquetas. Las combinaciones crean un producto cruzado completo de los conjuntos que participan en la combinación. El resultado es un conjunto de tuplas con cada permutación del elemento y los valores de la matriz de destino.
Una operación de combinación en nuestros productos y etiquetas de saco de dormir de ejemplo crea los siguientes elementos:
Elemento | Etiqueta |
---|---|
Saco de dormir de Maresse (6') Ming | Forma del saco: Momia |
Saco de dormir de Maresse (6') Ming | Aislamiento del saco: Relleno de plumón |
Saco de dormir Vareno (6') Cúrcuma | Aislamiento del saco: relleno sintético |
Saco de dormir Vareno (6') Cúrcuma | Grupo de colores: amarillo |
Saco de dormir Vareno (6') Cúrcuma | Forma del saco: Momia |
Esta es la consulta SQL y el conjunto de resultados JSON para una combinación que incluye varios elementos en el contenedor.
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"
}
]
Al igual que con el elemento único, puede aplicar un filtro aquí para localizar solo los elementos que coincidan con una etiqueta específica. Por ejemplo, esta consulta busca todos los elementos con una etiqueta denominada bag-shape-mummy
para cumplir el requisito inicial mencionado anteriormente en esta sección.
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"
}
]
También puede cambiar el filtro para obtener un conjunto de resultados diferente. Por ejemplo, esta consulta localiza todos los elementos que tienen una etiqueta denominada 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"
}
]