Sample Code

The Node.js 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.

Node.js 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.

'use strict';

var couchbase = require('couchbase');

var cluster = new couchbase.Cluster('couchbase://localhost');
cluster.authenticate('Administrator', 'password');

var bucket = cluster.openBucket('travel-sample');

bucket.mutateIn('hotel_10138')
    .upsert('discounts.jsmith123', '20', {xattr: true, createParents: true})
    .upsert('discounts.pjones356', '30', {xattr: true, createParents: true})
    .insert('discounts.jbrown789', '25', {xattr: true, createParents: true})
    .remove('discounts.jbrown789', {xattr: true})
    .execute(function(err, res) {
      if (err) {
        console.log('hotel_10138 update failed', err, res);
        process.exit(1);
        }

        bucket.mutateIn('hotel_10142')
          .upsert('discounts.jsmith123', '15', {xattr: true, createParents: true})
          .upsert('discounts.pjones356', '10', {xattr: true, createParents: true})
          .execute(function(err, res) {
            if (err) {
              console.log('hotel_10142 update failed', err, res);
              process.exit(1);
              }


              var qs = 'SELECT id, meta().id AS docID FROM `travel-sample`';
              var q = couchbase.N1qlQuery.fromString(qs);
              bucket.query(q).on('row', function(row) {
                  var docID = row.docID;

                  bucket.lookupIn(docID)
                      .get('discounts.jsmith123', {xattr: true})
                      .execute(function(err, res) {
                        if (!err) {
                          var discount = res.contentByIndex(0);
                          console.log(discount + ' - ' + 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:

'use strict';

var couchbase = require('couchbase');

var cluster = new couchbase.Cluster('couchbase://localhost');
cluster.authenticate('Administrator', 'password');

var bucket = cluster.openBucket('travel-sample');

var key = 'airline_17628';

// Touch the document to give it a TTL
bucket.touch(key, 300, function(err, res) {
  if (err) {
    throw err;
  }

  // Fetch the TTL of the document
  bucket.lookupIn(key)
    .get('$document.exptime', {xattrMacro: true})
    .execute(function(err, res) {
      if (err) {
        throw err;
      }

      var ttl = res.contentByIndex(0);
      console.log('Expiry value is: ' + ttl);

      // Reset the expiry so that the document does not expire
      bucket.touch(key, 0, function(err, res) {
        if (err) {
          throw err;
        }

        // Multiple paths can be access at once via subdoc. It's limited to 16 paths and xattrs have to be first.
        bucket.lookupIn(key)
          .get('$document.exptime', {xattrMacro: true})
          .get('$document.value_bytes', {xattrMacro: true})
          .get('callsign')
          .execute(function(err, res) {
            if (err) {
              throw err;
            }

            var ttl = res.contentByIndex(0);
            var size = res.contentByIndex(1);
            var callsign = res.contentByIndex(2);

            console.log('Expiry value is: ' + ttl);
            console.log('Size is ' + size);
            console.log('Callsign is ' + callsign);
          });
      })
    })
});