Selbstverknüpfungen in Azure Cosmos DB for NoSQL
GILT FÜR: NoSQL
In Azure Cosmos DB for NoSQL sind Daten schemalos und normalerweise denormalisiert. Anstatt Daten wie in einer relationalen Datenbank entitäts- und gruppenübergreifend zu verknüpfen, werden Verknüpfungen innerhalb eines einzelnen Elements durchgeführt. Insbesondere sind Verknüpfungen auf dieses Element begrenzt und können nicht übergreifend für mehrere Elemente und Container erfolgen.
Tipp
Wenn Sie feststellen, dass Sie element- und containerübergreifende Verknüpfungen benötigen, sollten Sie Ihr Datenmodell entsprechend überarbeiten, um dies zu vermeiden.
Selbstverknüpfung mit einem einzelnen Element
Nachfolgend sehen Sie ein Beispiel für eine Selbstverknüpfung innerhalb eines Elements. Stellen Sie sich einen Container mit einem einzelnen Element vor. Dieses Element stellt ein Produkt mit verschiedenen Tags dar:
[
{
"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"
}
]
}
]
Was ist, wenn Sie nach der Farbgruppe dieses Produkts suchen müssen? Normalerweise müssen Sie eine Abfrage schreiben, mit der durch einen Filter jeder potenzielle Index im tags
-Array auf einen Wert mit dem Präfix color-group-
überprüft wird.
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-")
Diese Vorgehensweise kann jedoch schnell nicht mehr praktikabel sein. Die Komplexität oder Länge der Abfragesyntax erhöht die Anzahl potenzieller Elemente im Array. Außerdem ist diese Abfrage nicht flexibel genug, um zukünftige Produkte zu verarbeiten, die mehr als drei Tags aufweisen könnten.
In einer herkömmlichen relationalen Datenbank werden die Tags in eine separate Tabelle unterteilt. Dann wird eine tabellenübergreifende Verknüpfung durchgeführt und ein Filter auf die Ergebnisse angewendet. In der API für NoSQL können Sie einen Selbstverknüpfungsvorgang innerhalb des Elements mithilfe des Schlüsselworts JOIN
ausführen.
SELECT
p.id,
p.sku,
t.slug
FROM
products p
JOIN
t IN p.tags
Diese Abfrage gibt ein einfaches Array mit einem Element für jeden Wert im Tagsarray zurück.
[
{
"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"
}
]
Nachfolgend wird die Abfrage aufgeschlüsselt. Die Abfrage hat nun zwei Aliase: p
für jedes Produktelement im Resultset und t
für das selbstverknüpfte tags
-Array. Das Schlüsselwort *
ist nur dann für das Projizieren aller Felder gültig, wenn es das Eingabeset ableiten kann, doch sind jetzt zwei Eingabesets vorhanden (p
und t
). Aufgrund dieser Einschränkung müssen wir die zurückgegebenen Felder explizit als id
und sku
vom Produkt zusammen mit slug
von den Tags definieren. Damit diese Abfrage besser lesbar und verständlicher ist, können wir das Feld id
löschen und einen Alias für das Feld name
des Tags verwenden, um es in tag
umzubenennen.
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"
}
]
Zum Schluss können wir einen Filter zum Auffinden des Tags color-group-purple
verwenden. Da wir das Schlüsselwort JOIN
verwendet haben, ist unser Filter flexibel genug, um eine beliebige Anzahl von Tags zu verarbeiten.
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"
}
]
Selbstverknüpfung mehrerer Elemente
Es folgt nun ein Beispiel, bei dem wir einen Wert innerhalb eines Arrays finden müssen, das in mehreren Elementen vorhanden ist. Bei diesem Beispiel gehen wir von einem Container mit zwei Produktelementen aus. Jedes Element enthält relevante Tags für dieses Element.
[
{
"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"
}
]
}
]
Was ist, wenn Sie jedes Element mit der Schlafsackform Mummy finden müssen? Sie können nach dem Tag bag-shape-mummy
suchen, doch müssten Sie eine komplexe Abfrage schreiben, die zwei Merkmale dieser Elemente umfasst:
Das Tag mit dem Präfix
bag-shape-
kommt in verschiedenen Indizes in jedem Array vor. Beim Vareno-Schlafsack ist das Tag das dritte Element (Index:2
). Beim Maresse-Schlafsack ist das Tag das erste Element (Index:0
).Das
tags
-Array für jedes Element weist eine andere Länge auf. Der Vareno-Schlafsack hat zwei Tags, der Maresse-Schlafsack hingegen drei Tags.
Hier bietet sich das Schlüsselwort JOIN
als ein hervorragendes Tool an, um ein Kreuzprodukt der Elemente und Tags zu erstellen. Durch Verknüpfungen wird ein komplettes Kreuzprodukt der an der Verknüpfung beteiligten Sets erstellt. Das Ergebnis ist eine Reihe von Tupeln mit jeder Permutation des Elements und den Werten innerhalb des Zielarrays.
Ein Verknüpfungsvorgang für unsere Musterschlafsackprodukte und Tags erstellt die folgenden Elemente:
Element | Tag |
---|---|
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 |
Hier sehen Sie die SQL-Abfrage und das JSON-Resultset für eine Verknüpfung, die mehrere Elemente im Container umfasst.
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"
}
]
Wie bei einem einzelnen Element können Sie auch hier einen Filter anwenden, um nur nach den Elementen zu suchen, die einem bestimmten Tag entsprechen. Diese Abfrage findet beispielsweise alle Elemente mit einem Tag namens bag-shape-mummy
, um die weiter oben genannte Anforderung zu erfüllen.
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"
}
]
Sie können den Filter auch ändern, um ein anderes Resultset zu erhalten. Mit dieser Abfrage werden beispielsweise alle Elemente gefunden, die ein Tag namens bag-insulation-synthetic-fill
aufweisen.
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"
}
]