Delen via


Self-joins in Azure Cosmos DB for NoSQL

VAN TOEPASSING OP: NoSQL

In Azure Cosmos DB for NoSQL zijn gegevens schemavrij 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 wilt deelnemen aan items en containers, 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": "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"
      }
    ]
  }
]

Wat moet u doen 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 een voorvoegsel van 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 bevatten.

In een traditionele relationele database worden de tags gescheiden in een afzonderlijke tabel en wordt een join tussen tabellen uitgevoerd met een filter dat op de resultaten wordt toegepast. 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": "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"
  }
]

Laten we de query 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 om alle velden te projecteren als deze de invoerset kan afleiden, maar er zijn nu twee invoersets (p en t). Vanwege deze beperking moeten we onze geretourneerde velden expliciet definiëren als id en sku van het product, samen met slug de tags. Om deze query gemakkelijker te lezen en te begrijpen, kunnen we het id veld verwijderen en een alias voor het veld van de tag name gebruiken om de naam ervan te tagwijzigen in.

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-purplete 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 zelf toevoegen

We gaan verder met een voorbeeld waarin we een waarde moeten vinden in een matrix die in meerdere items bestaat. Voor dit voorbeeld kunt u een container met twee productitems overwegen. Elk item bevat relevante tags voor dat item.

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

Wat moet u doen als u elk item met een mummietasshape wilt vinden? U kunt zoeken naar de tag bag-shape-mummy, maar u moet een complexe query schrijven die rekening maakt met twee kenmerken van deze items:

  • De tag met een bag-shape- voorvoegsel vindt plaats bij verschillende indexen in elke matrix. Voor de Vareno slaapzak is het label het derde item (index: 2). Voor de Maresse slaapzak is de tag het eerste item (index: 0).

  • De tags matrix voor elk item heeft een andere lengte. De Vareno slaapzak heeft twee tags terwijl de Maresse slaapzak drie heeft.

Hier is het JOIN trefwoord een geweldig hulpmiddel om een kruisproduct van de items en tags te maken. Joins maken een volledig crossproduct van de sets die deelnemen aan de join. Het resultaat is een set tuples met elke permutatie van het item en de waarden in de doelmatrix.

Een join-bewerking op onze voorbeeldproducten voor slaapzak en tags maakt de volgende items:

Artikel Tag
Maresse Slaapzak (6') Ming Tasshape: Mummie
Maresse Slaapzak (6') Ming Zakisolatie: omlaag vullen
Vareno Slaapzak (6') Kurkuma Zakisolatie: synthetische opvulling
Vareno Slaapzak (6') Kurkuma Kleurgroep: geel
Vareno Slaapzak (6') Kurkuma Tasshape: Mummie

Hier ziet u de SQL-query en de JSON-resultatenset voor een join met meerdere items in de container.

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 één 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 gevonden bag-shape-mummy die voldoet 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 worden bijvoorbeeld alle items met een tag met de naam gevonden 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"
  }
]