Sample Code
The Go SDK supports creation and handling of extended attributes.
Subdocument Operations and Extended Attributes
A high-level summary of extended attributes can be found in Extended Attributes. Extended attributes are handled by means of extensions to the Subdocument API.
Go Extended Attributes Example
The following code demonstrates how extended attributes can be used.
It assumes that Couchbase Server is established on localhost
; that the Full Administrator username and password are Administrator
and password
respectively; and that the travel-sample
bucket is installed.
For information on installing the travel-sample
bucket, see Sample Buckets.
package main
import (
"github.com/couchbase/gocb"
"fmt"
)
func main() {
cluster, _ := gocb.Connect("couchbase://localhost")
cluster.Authenticate(gocb.PasswordAuthenticator{
Username: "Administrator",
Password: "password",
})
bucket, _ := cluster.OpenBucket("travel-sample", "")
// Add key-value pairs to hotel_10138, representing traveller-Ids and associated discount percentages
bucket.MutateIn("hotel_10138", 0, 0).
UpsertEx("discounts.jsmith123", "20", gocb.SubdocFlagXattr|gocb.SubdocFlagCreatePath).
UpsertEx("discounts.pjones356", "30", gocb.SubdocFlagXattr|gocb.SubdocFlagCreatePath).
// The following lines, "insert" and "remove", simply demonstrate insertion and
// removal of the same path and value
InsertEx("discounts.jbrown789", "25", gocb.SubdocFlagXattr|gocb.SubdocFlagCreatePath).
RemoveEx("discounts.jbrown789", gocb.SubdocFlagXattr).
Execute()
// Add key - value pairs to hotel_10142, again representing traveller - Ids and associated discount percentages
bucket.MutateIn("hotel_10142", 0, 0).
UpsertEx("discounts.jsmith123", "15", gocb.SubdocFlagXattr|gocb.SubdocFlagCreatePath).
UpsertEx("discounts.pjones356", "10", gocb.SubdocFlagXattr|gocb.SubdocFlagCreatePath).
Execute()
q := gocb.NewN1qlQuery("SELECT id, META().id AS docID FROM `travel-sample`")
rows, _ := bucket.ExecuteN1qlQuery(q, nil)
var row struct {
DocID string `json:"docID"`
}
for rows.Next(&row) {
res, err := bucket.LookupIn(row.DocID).GetEx("discounts.jsmith123", gocb.SubdocFlagXattr).Execute()
if err == nil {
var discount string
res.ContentByIndex(0, &discount)
fmt.Printf("%s - %s\n", discount, row.DocID)
}
}
}
Virtual Extended Attributes Example
Using the Sub-Document API, Virtual XATTR can be used to fetch metadata about a document, via the $document
virtual XATTR.
A common use case is discovering documentation expiration metadata, or TTL:
package main
import (
"fmt"
"time"
"github.com/couchbase/gocb"
)
func main() {
cluster, err := gocb.Connect("couchbase://localhost")
if err != nil {
panic("Error connecting to cluster:" + err.Error())
}
err = cluster.Authenticate(gocb.PasswordAuthenticator{
Username: "test",
Password: "password",
})
if err != nil {
panic("Error creating authenticator:" + err.Error())
}
bucket, err := cluster.OpenBucket("travel-sample", "")
if err != nil {
panic("Error opening bucket:" + err.Error())
}
key := "airline_17628"
// Store the document
_, err = bucket.Touch(key, 0, 300)
if err != nil {
panic("Error performing touch:" + err.Error())
}
lookup := bucket.LookupIn(key).GetEx("$document.exptime", gocb.SubdocFlagXattr)
frag, err := lookup.Execute()
if err != nil {
panic(err)
}
var ttl uint32
err = frag.Content("$document.exptime", &ttl)
if err != nil {
panic(err)
}
fmt.Printf("Expiry value is %s\n", time.Unix(int64(ttl), 0).String())
// Reset the expiry so that the document does not expire.
_, err = bucket.Touch(key, 0, 0)
if err != nil {
panic("Error performing touch:" + err.Error())
}
// Multiple paths can be access at once via subdoc. It's limited to 16 paths and xattrs have to be first.
multiLookup := bucket.LookupIn(key).
GetEx("$document.exptime", gocb.SubdocFlagXattr).
GetEx("$document.value_bytes", gocb.SubdocFlagXattr).
Get("callsign")
multiFrag, err := multiLookup.Execute()
if err != nil {
panic(err)
}
// Errors ignored for brevity.
var size int
var callsign string
multiFrag.Content("$document.exptime", &ttl)
multiFrag.Content("$document.value_bytes", &size)
multiFrag.Content("callsign", &callsign)
fmt.Printf("Expiry value is %s\n", time.Unix(int64(ttl), 0).String())
fmt.Printf("Size is %d\n", size)
fmt.Printf("Callsign is %s\n", callsign)
}