Freigeben über


Self-Joins – Abfragesprache in Cosmos DB (in Azure und Fabric)

In der Abfragesprache sind Daten schemafrei und in der Regel denormalisiert. Anstatt Daten über Entitäten hinweg zu verknüpfen und Sätze wie in einer relationalen Datenbank zu verknüpfen, treten Verknüpfungen innerhalb eines einzelnen Elements auf. Insbesondere sind Verknüpfungen auf dieses Element zugeschnitten und können nicht über mehrere Elemente und Container hinweg erfolgen.

Tipp

Wenn Sie feststellen, dass Sie über Elemente und Container hinweg verknüpfen müssen, sollten Sie das Datenmodell umarbeiten, um dieses Antimuster zu vermeiden.

Self-Join mit einem einzelnen Element

Sehen wir uns ein Beispiel für eine Selbstverknnung innerhalb eines Elements an. Erwägen Sie einen Container mit einem einzelnen Element. Dieses Element stellt ein Produkt mit verschiedenen Größen dar:

[
  {
    "name": "Raiot Jacket",
    "sizes": [
      {
        "key": "s",
        "description": "Small"
      },
      {
        "key": "m",
        "description": "Medium"
      },
      {
        "key": "l",
        "description": "Large"
      },
      {
        "key": "xl",
        "description": "Extra Large"
      }
    ]
  }
]

Was geschieht, wenn Sie Produkte mit einer bestimmten Größe finden müssen? In der Regel müssen Sie eine Abfrage schreiben, die einen Filter enthält, der sizes jeden potenziellen Index im Array für einen Wert mit einem Präfix überprüft. In diesem Beispiel findet die Abfrage alle Produkte mit einer Größe, die mit Large:

SELECT
  *
FROM
  products p
WHERE
  p.sizes[0].description LIKE "%Large" OR
  p.sizes[1].description LIKE "%Large" OR
  p.sizes[2].description LIKE "%Large" OR
  p.sizes[3].description LIKE "%Large"

Diese Technik kann schnell unhaltbar werden. 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 möglicherweise mehr als drei Größen aufweisen.

In einer herkömmlichen relationalen Datenbank würden die Größen in eine separate Tabelle getrennt, und eine tabellenübergreifende Verknüpfung wird mit einem Filter ausgeführt, der auf die Ergebnisse angewendet wird. In der Abfragesprache können wir einen Self-Join-Vorgang innerhalb des Elements mithilfe des JOIN Schlüsselworts ausführen:

SELECT
  p.name,
  s.key,
  s.description
FROM
  products p
JOIN
  s in p.sizes

Diese Abfrage gibt ein einfaches Array mit einem Element für jeden Wert im Tagsarray zurück.

[
  {
    "name": "Raiot Jacket",
    "key": "s",
    "description": "Small"
  },
  {
    "name": "Raiot Jacket",
    "key": "m",
    "description": "Medium"
  },
  {
    "name": "Raiot Jacket",
    "key": "l",
    "description": "Large"
  },
  {
    "name": "Raiot Jacket",
    "key": "xl",
    "description": "Extra Large"
  }
]

Lassen Sie uns die Abfrage aufschlüsseln. Die Abfrage verfügt jetzt über zwei Aliase: p für jedes Produktelement im Resultset und s für das selbst verknüpfte sizes Array. Das * Schlüsselwort ist nur gültig, um alle Felder zu projizieren, wenn es den Eingabesatz ableiten kann, aber jetzt gibt es zwei Eingabesätze (p und t). Aufgrund dieser Einschränkung müssen wir unsere zurückgegebenen Felder explizit wie namekeyvom Produkt und description von den Größen definieren.

Schließlich können wir einen Filter verwenden, um die Größen zu finden, die enden mit Large. Da wir das JOIN Schlüsselwort verwendet haben, ist unser Filter flexibel genug, um eine beliebige variable Anzahl von Tags zu verarbeiten:

SELECT
  p.name,
  s.key AS size
FROM
  products p
JOIN
  s in p.sizes
WHERE
  s.description LIKE "%Large"
[
  {
    "name": "Raiot Jacket",
    "size": "l"
  },
  {
    "name": "Raiot Jacket",
    "size": "xl"
  }
]

Selbstverknnen mehrerer Elemente

Lassen Sie uns mit einem Beispiel fortfahren, in dem wir einen Wert innerhalb eines Arrays finden müssen, das in mehreren Elementen vorhanden ist. Betrachten Sie in diesem Beispiel einen Container mit zwei Produktelementen. Jedes Element enthält relevant colors für dieses Element.

[
  {
    "name": "Gremon Fins",
    "colors": [
      "science-blue",
      "turbo"
    ]
  },
  {
    "name": "Elecy Jacket",
    "colors": [
      "indigo-shark",
      "jordy-blue-shark"
    ]
  },
  {
    "name": "Tresko Pack",
    "colors": [
      "golden-dream"
    ]
  }
]

Was geschieht, wenn Sie jedes Element mit einer Farbe finden müssen, die im Namen enthalten ist blue ? Sie könnten manuell nach der Zeichenfolge bluesuchen, aber Sie müssen eine komplexe Abfrage schreiben, die zwei Merkmale dieser Elemente umfasst:

  • Die Farben mit einer blue Teilzeichenfolge treten bei verschiedenen Indizes in jedem Array auf. Für das Elecy Jacket Produkt ist die Farbe das zweite Element (Index: 1). Für das Gremon Fins Produkt ist das Tag das erste Element (Index: 0). Das Tresko Pack Produkt hat keine, die diese Teilzeichenfolge enthält.

  • Das colors Array für jedes Element ist eine andere Länge. Die Gremon Fins beiden Elecy Jacket Produkte haben zwei Farben, während das Tresko Pack Produkt nur eine hat.

Hier ist das JOIN Schlüsselwort ein großartiges Tool, um ein Kreuzprodukt der Elemente und Farben zu erstellen. Joins erstellen ein vollständiges Cross-Produkt der Gruppen, die an der Teilnahme teilnehmen. Das Ergebnis ist eine Gruppe von Tupeln mit jeder Permutation des Elements und den Werten innerhalb des Zielarrays.

Ein Verknüpfungsvorgang für unsere Beispielprodukte und -farben erstellt die folgenden Elemente:

Produkt Farbe
Gremon Fins science-blue
Gremon Fins turbo
Elecy Jacket indigo-shark
Elecy Jacket jordy-blue-shark
Tresko Pack golden-dream

In diesem Beispiel für die NoSQl-Abfrage wird das JOIN Schlüsselwort verwendet, um ein produktübergreifendes Element zu erstellen und alle Permutationen zurückgibt:

SELECT
  p.name,
  c AS color
FROM
  products p
JOIN
  c in p.colors
[
  {
    "name": "Elecy Jacket",
    "color": "indigo-shark"
  },
  {
    "name": "Elecy Jacket",
    "color": "jordy-blue-shark"
  },
  {
    "name": "Gremon Fins",
    "color": "science-blue"
  },
  {
    "name": "Gremon Fins",
    "color": "turbo"
  },
  {
    "name": "Tresko Pack",
    "color": "golden-dream"
  }
]

Genau wie bei dem einzelnen Element können Sie hier einen Filter anwenden, um nur Elemente zu finden, die einem bestimmten Tag entsprechen. Diese Abfrage findet beispielsweise alle Elemente mit einer Teilzeichenfolge, die enthält, blue um die zuvor in diesem Abschnitt erwähnte anfängliche Anforderung zu erfüllen.

SELECT
  p.name,
  c AS color
FROM
  products p
JOIN
  c in p.colors
WHERE
  c LIKE "%blue%"
[
  {
    "name": "Elecy Jacket",
    "color": "jordy-blue-shark"
  },
  {
    "name": "Gremon Fins",
    "color": "science-blue"
  }
]

Diese Abfrage kann noch weiter optimiert werden, um nur die Namen der Produkte zurückzugeben, die dem Filter entsprechen. In diesem Beispiel werden die Farbwerte nicht projiziert, der Filter funktioniert jedoch weiterhin wie erwartet:

SELECT VALUE
  p.name
FROM
  products p
JOIN
  c in p.colors
WHERE
  c LIKE "%blue%"
[
  "Elecy Jacket",
  "Gremon Fins"
]