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)
    }