Самостоятельное присоединение в Azure Cosmos DB для NoSQL

ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL

В Azure Cosmos DB для NoSQL данные являются свободными от схемы и обычно денормализованы. Вместо объединения данных между сущностями и наборами, например в реляционной базе данных, соединения происходят в одном элементе. В частности, соединения относятся к этому элементу и не могут выполняться в нескольких элементах и контейнерах.

Совет

Если вам нужно присоединиться к элементам и контейнерам, рассмотрите возможность повторной работы модели данных, чтобы избежать этого.

Самостоятельное присоединение к одному элементу

Рассмотрим пример самосоединения в элементе. Рассмотрим контейнер с одним элементом. Этот элемент представляет продукт с различными тегами:

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

Что делать, если вам нужно найти цветовую группу этого продукта? Как правило, необходимо написать запрос с проверкой каждого потенциального индекса в tags массиве для значения с префиксом 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-")

Этот метод может стать неприменимым быстро. Сложность или длина синтаксиса запроса увеличивает количество потенциальных элементов в массиве. Кроме того, этот запрос недостаточно гибкий для обработки будущих продуктов, которые могут иметь более трех тегов.

В традиционной реляционной базе данных теги будут разделены на отдельную таблицу, а соединение между таблицами выполняется с фильтром, примененным к результатам. В API для NoSQL можно выполнить операцию самостоятельного соединения в элементе с помощью ключевого JOIN слова.

SELECT
  p.id,
  p.sku,
  t.slug
FROM
  products p
JOIN
  t IN p.tags

Этот запрос возвращает простой массив с элементом для каждого значения в массиве тегов.

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

Давайте разберем запрос. Теперь запрос имеет два псевдонима: p для каждого элемента продукта в результирующем наборе и t для массива, присоединенного tags к нему. Ключевое * слово допустимо только для проецировать все поля, если он может выводить входной набор, но теперь есть два входных набора (p и t). Из-за этого ограничения необходимо явно определить возвращаемые поля как id и sku из продукта вместе с slug тегами. Чтобы упростить чтение и понимание этого запроса, можно удалить id поле и использовать псевдоним для поля тега name , чтобы переименовать его 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"
  }
]

Наконец, можно использовать фильтр для поиска тега color-group-purple. Так как мы использовали ключевое JOIN слово, наш фильтр достаточно гибкий, чтобы обрабатывать любое переменное количество тегов.

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

Самостоятельное присоединение нескольких элементов

Давайте перейдем к образцу, где необходимо найти значение в массиве, который существует в нескольких элементах. В этом примере рассмотрим контейнер с двумя элементами продукта. Каждый элемент содержит соответствующие теги для этого элемента.

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

Что если вам нужно найти каждый элемент с фигурой мумии мешок? Вы можете выполнить поиск тега bag-shape-mummy, но вам потребуется написать сложный запрос, который учитывает две характеристики этих элементов:

  • Тег с bag-shape- префиксом возникает по разным индексам в каждом массиве. Для спящего мешка Vareno тег является третьим элементом (индекс: 2). Для спящего мешка Maresse тег является первым элементом (индекс: 0).

  • Массив tags для каждого элемента имеет другую длину. Варено спящий мешок имеет два тега, в то время как Маресси спящий мешок имеет три.

JOIN Здесь ключевое слово является отличным инструментом для создания кросс-продукта элементов и тегов. Соединения создают полный кросс-продукт наборов, участвующих в присоединении. Результатом является набор кортежей с каждой перемутацией элемента и значений в целевом массиве.

Операция соединения с нашим примером продуктов и тегов спящего мешка создает следующие элементы:

Товар Тег
Маресси Спящий мешок (6') Мин Форма сумки: мумия
Маресси Спящий мешок (6') Мин Изоляция сумки: вниз заливка
Варено Спящий мешок (6') Турмерик Изоляция мешка: синтетическая заливка
Варено Спящий мешок (6') Турмерик Группа цветов: желтый
Варено Спящий мешок (6') Турмерик Форма сумки: мумия

Ниже приведен результирующий набор SQL-запросов и JSON для соединения, включающего несколько элементов в контейнер.

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

Как и в случае с одним элементом, можно применить фильтр здесь, чтобы найти только элементы, соответствующие определенному тегу. Например, этот запрос находит все элементы с тегом с именем bag-shape-mummy , чтобы соответствовать первоначальному требованию, упомянутому ранее в этом разделе.

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

Вы также можете изменить фильтр, чтобы получить другой результирующий набор. Например, этот запрос находит все элементы с именем 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"
  }
]