A newer version of this documentation is available.

View Latest

Sample Code

    +
    The Java SDK supports creation and handling of extended attributes.

    Sub-Document Operations and Extended Attributes

    A high-level summary of extended attributes can be found in Extended Attributes. Extended attributes (XATTRs) are accessed by means of extensions to the Sub-Document API.

    Java 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.

    import java.util.Arrays;
    import com.couchbase.client.core.message.kv.subdoc.multi.Lookup;
    import com.couchbase.client.java.Bucket;
    import com.couchbase.client.java.Cluster;
    import com.couchbase.client.java.CouchbaseCluster;
    import com.couchbase.client.java.cluster.UserRole;
    import com.couchbase.client.java.cluster.UserSettings;
    import com.couchbase.client.java.query.N1qlQuery;
    import com.couchbase.client.java.query.N1qlQueryResult;
    import com.couchbase.client.java.query.N1qlQueryRow;
    import com.couchbase.client.java.subdoc.*;
    
    public class CouchbaseExtendedAttributesDemo
    {
        public static void main(String [] args)
        {
            // Access the cluster that is running on the local host, authenticating with
            // the username and password of the Full Administrator. This
            // provides all privileges.
            //
            Cluster cluster = CouchbaseCluster.create("localhost");
    
            System.out.print("Authenticating as administrator." + "\n");
            cluster.authenticate("Administrator", "password");
    
            // Open the travel-sample bucket.
            //
            Bucket travelSample = cluster.openBucket("travel-sample");
    
            // Add key-value pairs to hotel_10138, representing traveller-Ids and associated
            // discount percentages.
            //
            travelSample.mutateIn("hotel_10138")
    
                .upsert("discounts.jsmith123", "20", new SubdocOptionsBuilder()
                    .createParents(true).xattr(true))
    
                .upsert("discounts.pjones356", "30", new SubdocOptionsBuilder()
                    .createParents(true).xattr(true))
    
                // The following lines, "insert" and "remove", simply demonstrate insertion and
                // removal of the same path and value.
                //
                .insert("discounts.jbrown789", "25", new SubdocOptionsBuilder()
                    .createParents(true).xattr(true))
    
                .remove("discounts.jbrown789", new SubdocOptionsBuilder().xattr(true))
    
                .execute();
    
            // Add key-value pairs to hotel_10142, again representing traveller-Ids and
            // associated discount percentages.
            //
            travelSample.mutateIn("hotel_10142")
    
                .upsert("discounts.jsmith123", "15", new SubdocOptionsBuilder()
                    .createParents(true).xattr(true))
    
                .upsert("discounts.pjones356", "10", new SubdocOptionsBuilder()
                    .createParents(true).xattr(true))
    
                .execute();
    
            // Create a user and assign roles. This user will search for their
            // available discounts.
            //
            System.out.print("Upserting new user." + "\n");
    
            cluster.clusterManager().upsertUser("jsmith123", UserSettings.build()
    
                .password("jsmith123pwd")
                .name("John Smith")
                .roles(Arrays.asList(
    
                    // Roles required for the reading of data from
                    // the bucket.
                    //
                    new UserRole("data_reader", "travel-sample"),
                    new UserRole("query_select", "travel-sample"),
    
                    // Roles required for the writing of data into
                    // the bucket.
                    //
                    new UserRole("data_writer", "travel-sample"),
                    new UserRole("query_insert", "travel-sample"),
                    new UserRole("query_delete", "travel-sample"),
    
                    // Role required for the creation of indexes
                    // on the bucket.
                    //
                    new UserRole("query_manage_index", "travel-sample")
            )));
    
            // As administrator, disconnect from cluster.
            //
            System.out.println("Administrator disconnecting.");
            cluster.disconnect();
    
            // Re-access the cluster as the created user.
            //
            System.out.print("User now connecting and authenticating."  + "\n");
            Cluster userCluster = CouchbaseCluster.create("localhost");
    
            String theusername = "jsmith123";
            String thepassword = "jsmith123pwd";
    
            userCluster.authenticate(theusername, thepassword);
    
            System.out.print("Opening travel-sample bucket as user."  + "\n");
            Bucket travelSampleForUser = userCluster.openBucket("travel-sample");
    
            // Perform a N1QL Query to return document IDs from the bucket. These IDs will be
            // used to reference each document in turn, and check for extended attributues
            // corresponding to discounts.
            //
            System.out.println("Searching for discounts, as user.");
            N1qlQueryResult result = travelSampleForUser.query(
                N1qlQuery.simple("SELECT id, meta(`travel-sample`).id " +
                    "AS docID FROM `travel-sample`")
            );
    
            // Get the docID of each document returned, and use the ID to determine whether
            // the extended attribute exists.
            //
            String theId = "";
            String resultsReturned = "";
            String searchPath = "discounts." + theusername;
    
            for (N1qlQueryRow row : result)
            {
                // Get the docID of the current document.
                //
                theId = row.value().getString("docID");
    
                // Determine whether a hotel-discount has been applied to this user.
                //
                DocumentFragment<Lookup> whetherDiscountExistsForUser =
                    travelSampleForUser.lookupIn(theId) .exists(searchPath,
                        new SubdocOptionsBuilder().xattr(true)).execute();
    
                // If so, get the discount-percentage.
                //
                if (whetherDiscountExistsForUser.content(searchPath, Boolean.class))
                {
                    DocumentFragment<Lookup> percentageValueOfDiscount =
                        travelSampleForUser.lookupIn(theId).get(searchPath,
                            new SubdocOptionsBuilder().xattr(true)).execute();
    
                    // If the percentage-value is greater than 15, include the document in the
                    // results to be returned.
                    //
                    if (Integer.parseInt(percentageValueOfDiscount.content(searchPath,
                            String.class)) > 15)
                    {
                        resultsReturned = resultsReturned + '\n' + travelSampleForUser.get(theId);
                    }
                }
            }
    
            // Display the results, which features only hotels offering more than a 15% discount
            // to the current user.
            //
            System.out.println("Results returned are: " + resultsReturned);
    
            // Disconnect user from the cluster.
            //
            userCluster.disconnect();
        }
    }

    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:

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import com.couchbase.client.core.message.kv.subdoc.multi.Lookup;
    import com.couchbase.client.java.Bucket;
    import com.couchbase.client.java.Cluster;
    import com.couchbase.client.java.CouchbaseCluster;
    import com.couchbase.client.java.subdoc.*;
    
    public class GetTTL
    {
        public static void main(String [] args)
        {
            // Access the cluster that is running on the local host, authenticating with
            // the username and password of the Full Administrator. This
            // provides all privileges.
            //
            Cluster cluster = CouchbaseCluster.create("localhost");
            cluster.authenticate("test", "password");
            Bucket test = cluster.openBucket("test");
    
            String key = "Perry";
    
            DocumentFragment<Lookup> click = test.lookupIn(key).get("click").execute();
            System.out.println("Click: " + click.content("click"));
    
            DocumentFragment<Lookup> ttl = test.lookupIn(key).get("$document.exptime", new SubdocOptionsBuilder().xattr(true)).execute();
            System.out.println("ttl: " + ttl.content("$document.exptime"));
    
            test.touch(key, 300);
    
            ttl = test.lookupIn(key).get("$document.exptime", new SubdocOptionsBuilder().xattr(true)).execute();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm.ss");
            System.out.println("ttl: " + sdf.format(new Date(ttl.content("$document.exptime", int.class))));
    
            test.touch(key, 0);
    
            //Multiple paths can be access at once via subdoc. It's limited to 16 paths and xattrs have to be first
            DocumentFragment<Lookup> multiSubPath = test.lookupIn(key).get("$document.exptime", new SubdocOptionsBuilder().xattr(true))
                                                                      .get("$document.value_bytes", new SubdocOptionsBuilder().xattr(true))
                                                                      .get("click")
                                                                      .execute();
    
            System.out.println("Click: " + multiSubPath.content("click"));
            System.out.println("ttl  : " + multiSubPath.content("$document.exptime"));
            System.out.println("Size : " + multiSubPath.content("$document.value_bytes"));
    
        }
    }