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 vanligtvis avnormaliserade. I stället för att koppla data mellan entiteter och uppsättningar, som i en relationsdatabas, sker kopplingar i ett enda objekt. Mer specifikt är kopplingar begränsade till objektet och kan inte förekomma i flera objekt och containrar.

Tips

Om du behöver ansluta mellan objekt och containrar bör du överväga att omarbeta datamodellen för att undvika detta.

Koppla själv med ett enda 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": "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"
      }
    ]
  }
]

Vad händer om du behöver hitta färggruppen för den här produkten? Vanligtvis behöver du 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 bli ohållbar snabbt. 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 korstabellkoppling 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": "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"
  }
]

Nu ska vi dela upp frågan. Frågan har nu två alias: p för varje produktobjekt i resultatuppsättningen och t för den själv anslutna tags matrisen. Nyckelordet * är bara 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"
  }
]

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

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 måste 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äcken 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 för våra exempel på sovsäcksprodukter och taggar skapar följande:

Objekt Tagg
Maresse Sovsäck (6') Ming Säckform: 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 Säckform: 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"
  }
]