개요
Key Valeu(KV)
또는 data service는 키를 알고 있는 데이터를 가져오거나 수정(mutate)하기 가장 쉬운 방법 제공
- 이 문서에서 커버하게 될 내용
- CRUD 작업
- 문서 만료(document expiration)
CAS(Compare And Swap)
로 낙관적 락(optimistic locking)
Concorrent
(병행, 동시) 문서 수정을 어떻게 다룰 것인지 제어하기 위해 사용
- 부주의로 어떤 변화가 유실되거나 다른 클라이언트에 의해 변화가 덮어쓰여지는 잠재적인 경합 상태(race condition)을 피하고 제어하는 것을 돕는다
CAS
값
- 항목의 현재 상태를 나타내며, 해당 항목이 변경될 때마다
CAS
값은 변한다
- 문서에 접근할 때마다 문서 메타데이터의 일부로 반환된다
replace
또는 remove
작업의 매개변수로 전달할 수 있다
- 애플리케이션이
CAS
를 제공하는 경우
애플리케이션의 CAS
== 문서의 CAS
→ 수정 작업 성공
애플리케이션의 CAS
!= 문서의 CAS
→ 수정 작업 실패
Docouments
document
는 데이터베이스의 항목(RDBMS에서는 row
)을 참조
document
는 유일한 ID
(RDBMS에서는 primary key
)를 가진다
document
는 실제 애플리케이션 데이터를 가진다
document
의 데이터 모델 참조
CRUD 작업
- Couchbase Server에 대한 핵심 인터페이스는 완전한
full document
에 대한 간단한 KV 작업이다
CREATE
$document = [
"foo" => "bar",
"bar" => "foo"
];
$res = $collection->insert("document-key-new", $document);
printf("document \"document-key\" has been created with CAS \"%s\"\n", $res->cas());
CAS
값을 설정하는 것은 낙관적 락
의 한 형태(a form of optimistic locking)
CAS
값은 항목의 현재 상태, 각 항목이 수정된 시간을 나타낸다
- get() 메서드 사용하여 완전한 `full document`를 가져올 수 있다
es = $collection->get("document-key");
$doc = $res->content();
printf("document \"document-key\" has content: \"%s\" CAS \"%s\"\n", json_encode($doc), $res->cas());
개요
TouchOption()
$opts = new TouchOptions();
$opts->timeout(500000 /* microseconds */);
$collection->touch($key, 60 /* seconds */);
getAndTouch()
$res = $collection->getAndTouch($key, 1 /* seconds */);
printf("[getAndTouch] document content: %s\n", var_export($res->content(), true));
sleep(2); // wait until the document will expire
try {
$collection->get($key);
} catch (Couchbase\DocumentNotFoundException $ex) {
printf("The document does not exist\n");
}
- 원자성 카운터
- 문서의 값을 원자적으로 증(increment)/감(decrement)
INCREMENT
// increment binary value by 1 (default)
$binaryCollection = $collection->binary();
$res = $binaryCollection->increment(<KEY>);
INCREMENT(with options)
$key = "phpDevguideExampleCounter";
$opts = new IncrementOptions();
# Create a document and assign it to 10
$opts = $opts->initial(10); # if it doesn't exist, counter works atomically by first creating a document
$opts = $opts->delta(2); # if it exist, the same method will increment/decrement per the "delta" parameter
$res = $binaryCollection->increment($key, $opts);
// Should print 10
printf("Initialized Counter: %d\n", $res->content());
DECREMENT
// decremtnt binary value by 1 (default)
$res = $binaryCollection->decrement("foo");
DECREMENT (with options)
$opts = new DecrementOptions();
$opts->initial(10)->delta(4);
// Decrement value by 4 to 8
$res = $binaryCollection->decrement($key, $opts);
// Should print 8
printf("Decremented Counter: %d\n", $res->content());
하위 문서(Sub-Document) 작업
개요
- 문서의
일부(parts)
에 효과적으로 접근하기 위해 사용
upsert
, replace
, 그리고 get
같은 완전한(full)
문서 작업보다 더 빠르고 네트워크 효율적일 수 있다
- 네트워크 통해 문서에 접근한 부분만 전달
- 내장된 병행 제어로 문서에 대한 원자적인, 안전한 수정이 가능하다
하위 문서(Sub-Document)
- 문서의 일부로서,
sub-documents
라 부른다
- 완전한 문서 조회는 전체 문서를 가져오고, 완전한 문서 업데이트는 완전한 문서를 전달해야 한다
- 반면 하위 문서 조회는 전체 문서의 일부만 반환하며, 하위 문서 언데이트는 수정된 일부만 전달하면 된다
- 단 여기서 기술한느 내용은
KV
요청에 대한 것이며, N1QL
쿼리에 대한 하위 문서 작업은 Querying with N1QL에 설명되어 있다
작업
예제 데이터
customer123.json
{
"name": "Douglas Reynholm",
"email": "douglas@reynholmindustries.com",
"addresses": {
"billing": {
"line1": "123 Any Street",
"line2": "Anytown",
"country": "United Kingdom"
},
"delivery": {
"line1": "123 Any Street",
"line2": "Anytown",
"country": "United Kingdom"
}
},
"purchases": {
"complete": [339, 976, 442, 666],
"abandoned": [157, 42, 999]
}
}
lookupIn(\Couchbase\Collection)
: 조회(Retrieving)
- \Couchbase\Collection\ class의
lookupIn
메서드 사용
name
, addresses.billing.country
, purchases.complete[0]
은 모두 유효한 경로(path)
다
lookup-in
작업은 특정 경로에 대한 문서를 문의(query)하고, 해당 경로들을 반환받는다
subdoc-get
하위 문서 작업을 사용하여 문서 경로를 조회하거나
subdoc-exists
하위 문서 작업을 사용하여 간단하게 경로가 존재하는지 문의할 수 있다
SUBDOC-GET: LookupGetSpec()
$result = $collection->lookupIn("customer123", [
new \Couchbase\LookupGetSpec("addresses.delivery.country")
]);
$country = $result->content(0);
printf("%s\n", $country);
// "United Kingdom"
SUBDOC-EXISTS: LookupExistsSpec()
$result = $collection->lookupIn("customer123", [
new \Couchbase\LookupExistsSpec("purchases.pending[-1]")
]);
printf("Path exists? %s\n", $result->exists(0) ? "true" : "false");
// Path exists? false
다중 조회 작업
$result = $collection->lookupIn("customer123", [
new \Couchbase\LookupGetSpec("addresses.delivery.country"),
new \Couchbase\LookupExistsSpec("purchases.pending[-1]")
]);
# $result는 \Couchbase\LookupInResult class
printf("%s\n", $result->content(0));
printf("Path exists? %s\n", $result->exists(1) ? "true" : "false");
// United Kingdom
// Path exists? false
mutateIn(\Couchbase\Collection)
: 수정(Mutating)
- \Couchbase\Collection\ class의
mutateIn
메서드 사용
atomic
작업으로, 만약 한 작업이라도 실패하면, 전체 문서가 변경없는 상태로 유지된다
- 문서의 하나 또는 그 이상의 경로를 수정
- 이 작업 중 가장 간단한 것은
subdoc-upsert
로, 완전한 문서(fulldoc) 레벨의 upsert
와 비슷하지만,
- 기존 경로의 값이 존재하면 수정
- 기존 경로의 값이 존재하지 않으면 새로 생성
SUBDOC-UPSERT: MutateUpsertSpec()
$result = $collection->mutateIn("customer123", [
new \Couchbase\MutateUpsertSpec("fax", "311-555-0151")
]);
SUBDOC-INSERT: MutateInsertSpec()
$result = $collection->mutateIn("customer123", [
new \Couchbase\MutateInsertSpec("purchases.complete", [42, true, "None"])
]);
// SubdocPathExistsError
SUBDOC-REMOVE/REPPLACE: MutateRemoveSpec()/MutateReplaceSpec()
$result = $collection->mutateIn("customer123", [
new \Couchbase\MutateRemoveSpec("addresses.billing"), // 삭제
new \Couchbase\MutateReplaceSpec("email", "dougr96@hotmail.com") // 치환
]);
SUBDOC-ARRAY-APPEND: MutateArrayAppendSpec()
/* BEFORE
"purchases": {
"complete": [339, 976, 442, 666],
"abandoned": [157, 42, 999]
}
*/
$result = $collection->mutateIn("customer123", [
new \Couchbase\MutateArrayAppendSpec("purchases.complete", [777])
]);
/* AFTER
"purchases": {
"complete": [339, 976, 442, 666, 777*],
"abandoned": [157, 42, 999]
}
*/
SUBDOC-ARRAY-PREPEND: MutateArrayPrependspec()
/* BEFORE
"purchases": {
"complete": [339, 976, 442, 666, 777],
"abandoned": [157, 42, 999]
}
*/
$result = $collection->MutateIn("customer123", [
new \Couchbase\MutateArrayPrependspec("purchases.abandoned", [18])
]);
/* AFTER
"purchases": {
"complete": [339, 976, 442, 666, 777],
"abandoned": [18*, 157, 42, 999]
}
*/
배열만 담는 문서 필요한 경우
$result = $collection->upsert("my_array", []);
$result = $collection->mutateIn("my_array", [
new \Couchbase\MutateArrayAppendSpec("", ["some element"])
]);
/* the document my_array:
[
"some element"
]
*/
COLLECTION OF MULTIPLE ELEMENTS
$collection_of_multiple_elements = [
[
"element1",
"element2",
"element3"
]
];
$result = $collection->mutateIn("my_array", [
new \Couchbase\MutateArrayAppendSpec("", $collection_of_multiple_elements)
]);
/* the document my_array:
[
"some element",
[
"element1",
"element2",
"element3"
]
]
*/
MULTIPLE ELEMENTS
$multiple_elements = [
"element1",
"element2",
"element3"
];
$result = $collection->mutateIn("my_array", [
new \Couchbase\MutateArrayAppendSpec("", $multiple_elements)
]);
/* the document my_array:
[
"some element",
[
"element1",
"element2",
"element3"
],
"element1",
"element2",
"element3"
]
*/