NoSQL용 Azure Cosmos DB의 자체 조인
적용 대상: NoSQL
NoSQL용 Azure Cosmos DB에서 데이터는 스키마가 없으며 일반적으로 비정규화됩니다. 관계형 데이터베이스에서처럼 엔터티 및 집합 간에 데이터를 조인하는 대신 조인은 단일 항목 내에서 발생합니다. 특히 조인은 해당 항목으로 범위가 지정되며 여러 항목 및 컨테이너에서 발생할 수 없습니다.
팁
항목 및 컨테이너에 조인해야 하는 경우 이를 방지하기 위해 데이터 모델을 다시 작업하는 것이 좋습니다.
단일 항목으로 자체 조인
항목 내에서 자체 조인의 예를 살펴보겠습니다. 단일 항목이 있는 컨테이너를 고려합니다. 이 항목은 다양한 태그가 있는 제품을 나타냅니다.
[
{
"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"
}
]
}
]
이 제품의 색상 그룹을 찾아야 하는 경우 어떻게 해야 합니까? 일반적으로 접두color-group-
사로 배열의 모든 잠재적 인덱스를 검사하는 필터가 있는 tags
쿼리를 작성해야 합니다.
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-")
이 기술은 신속하게 불가능해질 수 있습니다. 쿼리 구문 길이의 복잡성은 배열의 잠재적 항목 수에 따라 증가합니다. 또한 이 쿼리는 3개 이상의 태그가 있을 수 있는 향후 제품을 처리할 만큼 유연하지 않습니다.
기존 관계형 데이터베이스에서는 태그를 별도의 테이블로 구분하고 결과에 적용된 필터를 사용하여 테이블 간 조인을 수행합니다. NoSQL용 API에서 키워드를 사용하여 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"
}
]
쿼리를 세어보겠습니다. 이제 쿼리에는 결과 집합의 각 제품 항목과 t
자체 조인 배열에 대한 두 개의 별칭 p
이 tags
있습니다. 키워드는 *
입력 집합을 유추할 수 있는 경우에만 모든 필드를 프로젝션하는 데 유효하지만, 이제 두 개의 입력 집합(p
및 t
)이 있습니다. 이 제약 조건으로 인해 태그와 함께 slug
제품에서 반환된 필드를 id
sku
명시적으로 정의해야 합니다. 이 쿼리를 더 쉽게 읽고 이해할 수 있도록 필드를 삭제 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
각 항목의 배열 길이가 다릅니다. 바레노 침낭에는 두 개의 태그가 있으며 Maresse 침낭에는 3개의 태그가 있습니다.
JOIN
여기서 키워드는 항목 및 태그의 교차 곱을 만드는 데 유용한 도구입니다. 조인은 조인에 참여하는 집합의 전체 교차 제품을 만듭니다. 그 결과 항목의 모든 순열과 대상 배열 내의 값이 포함된 튜플 집합이 생성됩니다.
샘플 침낭 제품 및 태그에 대한 조인 작업은 다음 항목을 만듭니다.
Item | 태그 |
---|---|
마레스 침낭 (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"
}
]