Self-joins in Azure Cosmos DB for NoSQL
VAN TOEPASSING OP: NoSQL
In Azure Cosmos DB voor NoSQL zijn gegevens schemaloos en doorgaans gedenormaliseerd. In plaats van gegevens over entiteiten en sets samen te voegen, zoals in een relationele database, vinden joins plaats binnen één item. Joins zijn specifiek gericht op dat item en kunnen niet worden uitgevoerd voor meerdere items en containers.
Tip
Als u merkt dat u meerdere items en containers moet samenvoegen, kunt u overwegen om uw gegevensmodel opnieuw te bewerken om dit te voorkomen.
Self-join met één item
Laten we eens kijken naar een voorbeeld van een self-join binnen een item. Overweeg een container met één item. Dit item vertegenwoordigt een product met verschillende tags:
[
{
"id": "863e778d-21c9-4e2a-a984-d31f947c665c",
"categoryId": "e592b992-d453-42ee-a74e-0de2cc97db42",
"name": "Teapo Surfboard (6'10\") Grape",
"sku": "teapo-surfboard-72109",
"tags": [
{
"id": "556dc4f5-1dbd-41dc-9674-fda626e5d15c",
"slug": "tail-shape-swallow",
"name": "Tail Shape: Swallow"
},
{
"id": "ac097b9a-8a30-4fd1-8cb6-69d3388ee8a2",
"slug": "length-inches-82",
"name": "Length: 82 inches"
},
{
"id": "ce62b524-8e96-4999-b3e1-61ae7a672e2e",
"slug": "color-group-purple",
"name": "Color Group: Purple"
}
]
}
]
Wat gebeurt er als u de kleurgroep van dit product wilt vinden? Normaal gesproken moet u een query schrijven met een filter dat elke mogelijke index in de tags
matrix controleert op een waarde met het voorvoegsel 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-")
Deze techniek kan snel onhoudbaar worden. De complexiteit of lengte van de querysyntaxis verhoogt het aantal potentiële items in de matrix. Deze query is ook niet flexibel genoeg om toekomstige producten te verwerken, die mogelijk meer dan drie tags hebben.
In een traditionele relationele database worden de tags gescheiden in een afzonderlijke tabel en wordt een cross-table join uitgevoerd met een filter dat is toegepast op de resultaten. In de API voor NoSQL kunnen we een self-join-bewerking uitvoeren binnen het item met behulp van het JOIN
trefwoord.
SELECT
p.id,
p.sku,
t.slug
FROM
products p
JOIN
t IN p.tags
Deze query retourneert een eenvoudige matrix met een item voor elke waarde in de tagsmatrix.
[
{
"id": "863e778d-21c9-4e2a-a984-d31f947c665c",
"sku": "teapo-surfboard-72109",
"slug": "tail-shape-swallow"
},
{
"id": "863e778d-21c9-4e2a-a984-d31f947c665c",
"sku": "teapo-surfboard-72109",
"slug": "length-inches-82"
},
{
"id": "863e778d-21c9-4e2a-a984-d31f947c665c",
"sku": "teapo-surfboard-72109",
"slug": "color-group-purple"
}
]
Laten we de query eens opsplitsen. De query heeft nu twee aliassen: p
voor elk productitem in de resultatenset en t
voor de zelf-gekoppelde tags
matrix. Het *
trefwoord is alleen geldig voor het project van alle velden als het de invoerset kan afleiden, maar nu zijn er twee invoersets (p
en t
). Vanwege deze beperking moeten we de geretourneerde velden expliciet definiëren als id
en sku
van het product, samen met slug
van de tags. Om deze query beter leesbaar en begrijpelijker te maken, kunnen we het id
veld verwijderen en een alias voor het veld van name
de tag gebruiken om de naam ervan te wijzigen 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"
}
]
Ten slotte kunnen we een filter gebruiken om de tag color-group-purple
te vinden. Omdat we het JOIN
trefwoord hebben gebruikt, is ons filter flexibel genoeg om elk variabel aantal tags te verwerken.
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"
}
]
Meerdere items automatisch samenvoegen
We gaan verder met een voorbeeld waarin we een waarde moeten vinden in een matrix die bestaat in meerdere items. In dit voorbeeld kunt u een container met twee productitems gebruiken. Elk item bevat relevante tags voor dat item.
[
{
"id": "80d62f31-9892-48e5-9b9b-5714d551b8b3",
"categoryId": "19cd9b93-bdc5-4082-97fe-2c80c2fd77dd",
"categoryName": "Sleeping Bags",
"name": "Maresse Sleeping Bag (6') Ming",
"sku": "maresse-sleeping-bag-65503",
"tags": [
{
"id": "f50f3ee1-e150-4821-922b-ebe6ad82f313",
"slug": "bag-shape-mummy",
"name": "Bag Shape: Mummy"
},
{
"id": "8564fb66-63ea-464a-872a-7598433b9479",
"slug": "bag-insulation-down-fill",
"name": "Bag Insulation: Down Fill"
}
]
},
{
"id": "6e9f51c1-6b45-440f-af5a-2abc96cd083d",
"categoryId": "19cd9b93-bdc5-4082-97fe-2c80c2fd77dd",
"categoryName": "Sleeping Bags",
"name": "Vareno Sleeping Bag (6') Turmeric",
"sku": "vareno-sleeping-bag-65508",
"tags": [
{
"id": "e02502ce-367e-4fb4-940e-93d994fa6062",
"slug": "bag-insulation-synthetic-fill",
"name": "Bag Insulation: Synthetic Fill"
},
{
"id": "c0844995-3db9-4dbb-8d9d-d2c2a6151b94",
"slug": "color-group-yellow",
"name": "Color Group: Yellow"
},
{
"id": "f50f3ee1-e150-4821-922b-ebe6ad82f313",
"slug": "bag-shape-mummy",
"name": "Bag Shape: Mummy"
}
]
}
]
Wat als je elk item met de vorm van een mummietas moet vinden? U kunt zoeken naar de tag bag-shape-mummy
, maar u moet een complexe query schrijven die rekening houdt met twee kenmerken van deze items:
De tag met een
bag-shape-
voorvoegsel vindt plaats in verschillende indexen in elke matrix. Voor de Vareno-slaapzak is het label het derde item (index:2
). Voor de Maresse-slaapzak is het label het eerste item (index:0
).De
tags
matrix voor elk item heeft een andere lengte. De Vareno slaapzak heeft twee labels en de Maresse slaapzak heeft er drie.
Hier is het JOIN
trefwoord een uitstekend hulpmiddel om een cross-product van de items en tags te maken. Joins maken een volledig cross-product van de sets die deelnemen aan de join. Het resultaat is een set tuples met elke permutatie van het item en de waarden binnen de doelmatrix.
Een join-bewerking op onze voorbeeldproducten en tags voor slaapzakken zorgt voor de volgende items:
Item | Tag |
---|---|
Maresse Slaapzak (6') Ming | Vorm van zak: Mummy |
Maresse Slaapzak (6') Ming | Zakisolatie: Donsopvulling |
Vareno Slaapzak (6') Kurkuma | Isolatie van zak: synthetische opvulling |
Vareno Slaapzak (6') Kurkuma | Kleurgroep: Geel |
Vareno Slaapzak (6') Kurkuma | Vorm van zak: Mummy |
Hier ziet u de SQL-query- en JSON-resultatenset voor een join die meerdere items in de container bevat.
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"
}
]
Net als bij het ene item kunt u hier een filter toepassen om alleen items te vinden die overeenkomen met een specifieke tag. Met deze query worden bijvoorbeeld alle items met een tag met de naam bag-shape-mummy
gevonden om te voldoen aan de initiële vereiste die eerder in deze sectie is vermeld.
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"
}
]
U kunt het filter ook wijzigen om een andere resultatenset op te halen. Met deze query vindt u bijvoorbeeld alle items met een tag met de naam 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"
}
]