Dela via


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"
  }
]