Självkopplingar i Azure Cosmos DB för NoSQL
GÄLLER FÖR: NoSQL
I Azure Cosmos DB för NoSQL är data schemafria och avnormaliserade. I stället för att koppla data mellan entiteter och uppsättningar, som i en relationsdatabas, sker kopplingar inom ett enda objekt. Mer specifikt är kopplingar begränsade till det objektet och kan inte förekomma i flera objekt och containrar.
Dricks
Om du behöver koppla mellan objekt och containrar bör du överväga att omarbeta datamodellen för att undvika detta.
Självkoppling med ett enskilt objekt
Nu ska vi titta på ett exempel på en självkoppling i ett objekt. Överväg en container med ett enda objekt. Det här objektet representerar en produkt med olika taggar:
[
{
"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"
}
]
}
]
Vad händer om du behöver hitta färggruppen för den här produkten? Vanligtvis skulle du behöva skriva en fråga som har ett filter som kontrollerar varje potentiellt index i matrisen tags
för ett värde med prefixet 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-")
Den här tekniken kan snabbt bli ohållbar. Frågesyntaxens komplexitet eller längd ökar antalet potentiella objekt i matrisen. Dessutom är den här frågan inte tillräckligt flexibel för att hantera framtida produkter, som kan ha fler än tre taggar.
I en traditionell relationsdatabas skulle taggarna delas upp i en separat tabell och en koppling mellan tabeller utförs med ett filter som tillämpas på resultaten. I API:et för NoSQL kan vi utföra en självkopplingsåtgärd i objektet med hjälp av nyckelordet JOIN
.
SELECT
p.id,
p.sku,
t.slug
FROM
products p
JOIN
t IN p.tags
Den här frågan returnerar en enkel matris med ett objekt för varje värde i taggar-matrisen.
[
{
"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"
}
]
Nu ska vi dela upp frågan. Frågan har nu två alias: p
för varje produktartikel i resultatuppsättningen och t
för den själv anslutna tags
matrisen. Nyckelordet *
är endast giltigt för att projicera alla fält om det kan härleda indatauppsättningen, men nu finns det två indatauppsättningar (p
och t
). På grund av den här begränsningen måste vi uttryckligen definiera våra returnerade fält som id
och sku
från produkten tillsammans med slug
från taggarna. För att göra den här frågan enklare att läsa och förstå kan vi släppa fältet id
och använda ett alias för taggens name
fält för att byta namn på det till 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"
}
]
Slutligen kan vi använda ett filter för att hitta taggen color-group-purple
. Eftersom vi använde nyckelordet JOIN
är vårt filter tillräckligt flexibelt för att hantera valfritt variabelt antal taggar.
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"
}
]
Ansluta flera objekt själv
Nu ska vi gå vidare till ett exempel där vi behöver hitta ett värde i en matris som finns i flera objekt. I det här exemplet bör du överväga en container med två produktobjekt. Varje objekt innehåller relevanta taggar för objektet.
[
{
"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"
}
]
}
]
Tänk om du behövde hitta alla föremål med en mumiepåseform ? Du kan söka efter taggen bag-shape-mummy
, men du skulle behöva skriva en komplex fråga som står för två egenskaper för dessa objekt:
Taggen med ett
bag-shape-
prefix inträffar vid olika index i varje matris. För vareno-sovsäcken är taggen det tredje objektet (index:2
). För Maresse-sovsäcken är taggen det första objektet (index:0
).Matrisen
tags
för varje objekt är en annan längd. Vareno sovsäck har två taggar medan Maresse sovsäck har tre.
Här är nyckelordet JOIN
ett bra verktyg för att skapa en korsprodukt av objekten och taggarna. Kopplingar skapar en fullständig korsprodukt av de uppsättningar som deltar i kopplingen. Resultatet är en uppsättning tupplar med varje permutation av objektet och värdena i målmatrisen.
En kopplingsåtgärd på våra exempel på sovsäcksprodukter och taggar skapar följande:
Artikel | Tagg |
---|---|
Maresse Sovsäck (6') Ming | Påsform: Mamma |
Maresse Sovsäck (6') Ming | Påsisolering: Nedfyllning |
Vareno sovsäck (6') Gurkmeja | Påsisolering: Syntetisk fyllning |
Vareno sovsäck (6') Gurkmeja | Färggrupp: Gul |
Vareno sovsäck (6') Gurkmeja | Påsform: Mamma |
Här är SQL-frågan och JSON-resultatuppsättningen för en koppling som innehåller flera objekt i containern.
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"
}
]
Precis som med det enskilda objektet kan du använda ett filter här för att bara hitta objekt som matchar en specifik tagg. Den här frågan hittar till exempel alla objekt med en tagg med namnet bag-shape-mummy
för att uppfylla det ursprungliga kravet som nämndes tidigare i det här avsnittet.
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"
}
]
Du kan också ändra filtret för att få en annan resultatuppsättning. Den här frågan hittar till exempel alla objekt som har en tagg med namnet 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"
}
]