JSON 피클에 있을 때는 N1QL을 사용하세요. - Confucius
JSON 데이터 모델의 경우, 대략적으로 컬렉션을 테이블로, JSON 문서를 비정규화된 행으로, 필드 이름을 열로 생각하라는 조언이 있습니다. 이 모든 것은 권장 사항을 엄격하게 준수하는 경우 Couchbase 및 MongoDB와 같은 데이터베이스에 적용됩니다. 사용자가 단순히 키-값 쌍 모델을 따르지 않는 데에는 여러 가지 이유가 있습니다. 항상 주요 이유는 다음과 같습니다.
데이터베이스와 쿼리 언어가 해당 상황을 처리하지 못하면 정교한 재설계를 거쳐야 합니다. 단순히 정보에 액세스하는 것뿐만 아니라 JSON에 대한 쿼리를 효율적으로 만들려면 어떻게 해야 하나요? 색인해야 할 필드의 이름조차 모르시나요? 다행히도 Couchbase N1QL에는 유연한 메타데이터를 처리할 수 있는 다양한 쿼리 및 인덱스 기능이 있습니다.
이러한 사용 사례를 고려해 보겠습니다.
사용 사례 1: 가치 혁신.
다음은 JSON 문서 샘플입니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "cname": "제인 스미스", "dob" : "1990-01-30", "전화" : [ "+1 510-523-3529", "+1 650-392-4923" ], "청구": [ { "type": "비자", "cardnum": "5827-2842-2847-3909", "만료": "2019-03" }, { "type": "master", "cardnum": "6274-2542-5847-3949", "만료": "2018-12" } ] } |
JSON 데이터 모델은 간단히 키-값 쌍의 집합으로 설명됩니다. 각 키는 문자열이며, 해당 키의 계층 수준과 값이 스칼라, 객체 또는 배열일 수 있다는 점에서 고유합니다. 엄격한 정의는 다음과 같습니다. 여기. JSON은 또한 자체 설명이 가능하기 때문에 데이터베이스 문서 모델. 모든 고객이 고정된 전화번호나 자동차 또는 기타 유형의 속성을 보유할 필요는 없습니다.
위의 동일한 정보를 정보 손실 없이 아래 JSON으로 재구성할 수 있지만 일부 암시적 스키마는 다음과 같습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "제인 스미스": "1990-01-30", "home": "+1 510-523-3529", "office": "+1 650-392-4923", "청구": [ { "비자": "5827-2842-2847-3909", "만료": "2019-03" }, { "master": "6274-2542-5847-3949", "만료": "2018-12" } ] } |
단순히 문서를 넣고 설정하는 것이라면 이 모든 것이 괜찮습니다. JSON의 구조가 무엇이든 상관없습니다. 단순히 앞뒤로 오가기만 하면 됩니다.
이제 이것이 쿼리에 어떤 영향을 미치는지 살펴보겠습니다.
Q1: 선택 * FROM 고객 어디 cxname = "Jane Smith";
새 JSON 모델에서는 다음과 같은 필드 이름이 없습니다. cxname 여기를 클릭하세요.
|
1 2 3 4 |
Q2: 선택 p FROM 사람들 p 어디 ANY o IN object_names(p) 만족 o = "제인 스미스" END |
마법의 힘 object_pairs() 함수를 사용하시나요? 이 함수는 JSON {"key":"value"} 쌍을 이름-값 쌍의 배열로 변환합니다. 다음은 예제입니다.
|
1 2 3 4 5 6 7 8 9 |
선택 OBJECT_NAMES({"제인 스미스": "1990-01-30", "home": "+1 510-523-3529"}) "$1": [ "제인 스미스", "home" ] } |
OBJECT_NAMES() 함수는 키(여기서는 "Jane Smith")를 추출하여 값으로 반환한 다음 인덱싱할 수 있습니다. 이 함수는 하나의 값이 아니라 '키 이름'의 배열을 값으로 반환하므로 배열 인덱스를 만들어야 합니다. 쿼리 Q1과 Q2는 각각의 데이터 모델에 대해 동일한 작업을 수행합니다. 하지만 각 쿼리가 밀리초 단위로 실행되어야 합니다.
1분기의 경우, cxname에 인덱스를 생성하기만 하면 됩니다.
만들기 INDEX ix_cxname 켜기 고객(cxname)
2분기의 경우
만들기 INDEX ix_people 켜기 사람들(DISTINCT OBJECT_NAMES(self))
이 지수를 사용하면 2분기에는 이 지수를 사용하는 요금제가 제공됩니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
{ "#operator": "DistinctScan", "scan": { "#operator": "IndexScan3", "as": "p", "카디널리티": 1, "cost": 0.273, "index": "ix_people", "index_id": "4a2df8dd85543aa4", "index_projection": { "primary_key": true }, "키스페이스": "사람들", "네임스페이스": "default", "spans": [ { "정확한": true, "범위": [ { "high": "\"제인 스미스\"", "포함": 3, "low": "\"제인 스미스\"" } ] } ], |
사용 사례 2: 동적 키 이름.
이 사용 사례는 카우치베이스 포럼 게시물.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "id": "05a9b954-bdee-4d7f-9715-8e9e08f8cb75", "type": "기사", "번역": { "en": "안녕하세요", "de": "안녕하세요", "fr": "봉쥬르", "es": "Hola" } } |
질문: 내에서 값을 인덱싱하는 가장 좋은 방법은 무엇일까요? 번역 동적으로? 즉, 모든 키를 인덱싱하는 일반 인덱스입니다. 번역 객체입니다.
단순히 항상 영어 문서를 쿼리해야 하는 경우, 다음과 같이 하세요. 다음이 포함된 모든 문서를 쿼리합니다. translations.en = "안녕하세요".
항상 영어로 된 번역을 찾고 있다면 transactions.en에 색인을 생성하면 됩니다.
|
1 2 3 4 |
만들기 INDEX ix_tren 켜기 정보(번역.en); 선택 * FROM 정보 어디 translation.en = "안녕하세요"; |
키가 동적일 경우 데이터에 어떤 특정 언어가 포함될지, 어떤 언어가 쿼리될 수 있는지 알 수 없으므로 둘 다 동적으로 만들어야 합니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* 쿼리 */ 선택 * FROM 정보 어디 ANY v IN 오브젝트_쌍(번역) 만족 [v.name,v.val] = ["en", "안녕하세요"] END /* 색인 */ 만들기 INDEX ix_infoname 켜기 정보 ( DISTINCT 배열 [v.name, v.val ] FOR v IN 오브젝트_쌍(번역) END ) |
다음은 인덱스가 실제로 선택되고 술어가 인덱스 스캔으로 푸시되는지 확인하기 위한 설명입니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
{ "#operator": "DistinctScan", "scan": { "#operator": "IndexScan3", "카디널리티": 0.5, "cost": 0.1665, "index": "ix_infoname", "index_id": "BBBFD22A022FB75", "index_projection": { "primary_key": true }, "키스페이스": "정보", "네임스페이스": "default", "spans": [ { "정확한": true, "범위": [ { "high": "[\"en\", \"Hello\"]", "포함": 3, "low": "[\"en\", \"Hello\"]" } ] } ], "사용": "gsi" } }, |
인덱스 정의가 평소보다 조금 더 복잡해 보이더라도 걱정하지 마세요. 인덱스 어드바이저가 도와드리겠습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
조언 선택 * FROM 정보 어디 ANY v IN 오브젝트_쌍(번역) 만족 [v.name,v.val] = ["en", "안녕하세요"] END { "index_statement": "CREATE INDEX adv_DISTINCT_object_pairs_translations_name_val ON `info`(DISTINCT ARRAY [`v`.`name`, `v`.`val`] FOR v in object_pairs((`translations`)) END)", "키스페이스_알리어스": "정보", "추천_규칙": "인덱스 키는 술어 유형의 순서를 따릅니다: 2. 같음/없음/누락." } |
평가 중인 각 표현식 위에 표현식을 추가할 수도 있습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
조언 선택 * FROM 정보 어디 ANY v IN 오브젝트_쌍(번역) 만족 [LOWER(v.이름),LOWER(v.val)] = ["en", "안녕하세요"] END { "index_statement": "CREATE INDEX adv_DISTINCT_object_pairs_translations_lower_name_lower_val ON `info`(DISTINCT ARRAY [lower((`v`.`name`)), lower((`v`.`val`))] FOR v in object_pairs((`translations`)) END)", "키스페이스_알리어스": "정보", "추천_규칙": "인덱스 키는 술어 유형의 순서를 따릅니다: 2. 같음/없음/누락." } |
더 많은 개체 함수
N1QL에는 다음과 같은 추가 기능이 있습니다. 객체 및 중첩된 데이터 함수를 사용하여 복잡한 데이터 모델에 도움을 받을 수 있습니다. 객체 함수의 전체 집합과 토큰 함수.
참조: