Self-join in Azure Cosmos DB per NoSQL
SI APPLICA A: NoSQL
In Azure Cosmos DB per NoSQL i dati sono privi di schema e in genere denormalizzati. Anziché unire dati tra entità e set, come in un database relazionale, i join si verificano all'interno di un singolo elemento. In particolare, i join hanno come ambito tale elemento e non possono verificarsi tra più elementi e contenitori.
Suggerimento
Se è necessario creare un join tra elementi e contenitori, è consigliabile rielaborare il modello di dati per evitare questo problema .
Self-join con un singolo elemento
Di seguito viene illustrato un esempio di self-join all'interno di un elemento. Si consideri un contenitore con un singolo elemento. Questo elemento rappresenta un prodotto con vari tag:
[
{
"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"
}
]
}
]
Cosa succede se è necessario trovare il gruppo di colori di questo prodotto? In genere, sarebbe necessario scrivere una query con un filtro che controlla ogni potenziale indice nella tags
matrice per un valore con un prefisso .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-")
Questa tecnica può diventare insostenibile rapidamente. La complessità o la lunghezza della sintassi della query aumenta il numero di elementi potenziali nella matrice. Inoltre, questa query non è sufficientemente flessibile per gestire i prodotti futuri, che possono avere più di tre tag.
In un database relazionale tradizionale i tag vengono separati in una tabella separata e viene eseguito un join tra tabelle con un filtro applicato ai risultati. Nell'API per NoSQL è possibile eseguire un'operazione di self join all'interno dell'elemento usando la JOIN
parola chiave .
SELECT
p.id,
p.sku,
t.slug
FROM
products p
JOIN
t IN p.tags
Questa query restituisce una matrice semplice con un elemento per ogni valore nella matrice di tag.
[
{
"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"
}
]
Suddividere la query. La query ha ora due alias: p
per ogni elemento del prodotto nel set di risultati e t
per la matrice self-join tags
. La *
parola chiave è valida solo per proiettare tutti i campi se può dedurre il set di input, ma ora sono presenti due set di input (p
e t
). A causa di questo vincolo, è necessario definire in modo esplicito i campi restituiti come id
e sku
dal prodotto insieme slug
ai tag . Per semplificare la lettura e la comprensione di questa query, è possibile eliminare il id
campo e usare un alias per il campo del name
tag per rinominarlo in 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"
}
]
Infine, è possibile usare un filtro per trovare il tag color-group-purple
. Poiché è stata usata la parola chiave , il JOIN
filtro è sufficientemente flessibile per gestire qualsiasi numero variabile di tag.
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"
}
]
Aggiunta automatica di più elementi
Si passerà a un esempio in cui è necessario trovare un valore all'interno di una matrice presente in più elementi. Per questo esempio, si consideri un contenitore con due elementi di prodotto. Ogni elemento contiene tag pertinenti per tale 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"
}
]
}
]
E se avessi bisogno di trovare ogni elemento con una forma borsa mummia ? È possibile cercare il tag bag-shape-mummy
, ma è necessario scrivere una query complessa che conti per due caratteristiche di questi elementi:
Il tag con un
bag-shape-
prefisso si verifica in indici diversi in ogni matrice. Per il contenitore a pelo Vareno , il tag è il terzo elemento (indice:2
). Per il sacco a pelo Maresse , il tag è il primo elemento (indice:0
).La
tags
matrice per ogni elemento è una lunghezza diversa. Il sacco a pelo Vareno ha due tag mentre il sacco a pelo Maresse ha tre.
In questo caso, la JOIN
parola chiave è un ottimo strumento per creare un prodotto incrociato degli elementi e dei tag. I join creano un prodotto incrociato completo dei set che partecipano al join. Il risultato è un set di tuple con ogni permutazione dell'elemento e i valori all'interno della matrice di destinazione.
Un'operazione di join sui prodotti e i tag del sacco a pelo di esempio crea gli elementi seguenti:
Articolo | Tag |
---|---|
Maresse Sleeping Bag (6') Ming | Forma borsa: Mummia |
Maresse Sleeping Bag (6') Ming | Isolamento sacchetto: riempimento giù |
Vareno Sleeping Bag (6') Curcuma | Isolamento sacchetto: riempimento sintetico |
Vareno Sleeping Bag (6') Curcuma | Gruppo colori: giallo |
Vareno Sleeping Bag (6') Curcuma | Forma borsa: Mummia |
Ecco la query SQL e il set di risultati JSON per un join che include più elementi nel contenitore.
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"
}
]
Proprio come con il singolo elemento, è possibile applicare un filtro qui per trovare solo gli elementi che corrispondono a un tag specifico. Ad esempio, questa query trova tutti gli elementi con un tag denominato bag-shape-mummy
per soddisfare il requisito iniziale indicato in precedenza in questa sezione.
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"
}
]
È anche possibile modificare il filtro per ottenere un set di risultati diverso. Ad esempio, questa query trova tutti gli elementi con un tag denominato 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"
}
]
Contenuto correlato
- Clausola
SELECT
- Clausola
FROM
- Subqueries (Sottoquery)