You are currently viewing an older version of the docs. Go to the latest version →

Node API

Installation

FoundationDB’s Node.js API is available as a tarball from from the community site. It is to be installed with npm. For example, on Linux:

user@host$ npm install fdb-node-0.2.1-2-linux-x64.tar.gz

For the API to function, the FoundationDB client binaries must be installed (see Installing FoundationDB client binaries).

API versioning

When you require the fdb module, it exposes only one useful symbol:

apiVersion(version)

Returns the FoundationDB module corresponding with a particular API version. This allows future versions of FoundationDB to make API changes without breaking existing programs. The current version of the API is 21.

For example:

var fdb = require('fdb').apiVersion(21)
Throws an error if the specified version is not supported.
Throws an error if apiVersion has been called previously with a different version.

Note

You must call apiVersion(...) to get access to the fdb module.

For API changes between version 14 and 21 (for the purpose of porting older programs), see Release Notes.

Opening a database

After importing the fdb module and selecting an API version, you probably want to open a Database(). The simplest way of doing this is using open():

var fdb = fdb.apiVersion(21)
fdb.open(null, null, function(err, db) {
    //Use db here
});
fdb.open(clusterFile, dbName, callback)

Initializes the FoundationDB API, connects to the cluster specified by the cluster file, and opens the database with the specified name. In many cases, it is not necessary to pass any parameters to this function, since it will use a Default cluster file to connect to a cluster.

When finished, the callback is called with a Database() object.

Note

In this release, dbName must be “DB”.

Note

fdb.open() combines the effect of fdb.init(), fdb.createCluster(), and Cluster.openDatabase().

Throws an error if the network was unable to be initialized.

fdb.init()

Initializes the FoundationDB API, creating a thread for the FoundationDB client and initializing the client’s networking engine.

Throws an error if the network was unable to be initialized.

fdb.createCluster(clusterFile, callback)

Connects to the cluster specified by clusterFile, or by a Default cluster file if clusterFile is null or undefined.

When finished, the callback is called with a Cluster() object.

fdb.options

A singleton providing options which affect the entire FoundationDB client. Unless otherwise stated, options need to be specified before invoking fdb.open() or fdb.init().

fdb.options.setTraceEnable(outputDirectory)

Enables trace file generation on this FoundationDB client. Trace files will be generated in the specified output directory. If the directory is specified as null or undefined, then the output directory will be the current working directory.

Cluster objects

class Cluster()
Cluster.openDatabase(name="DB", callback)

Opens a database with the given name.

When finished, the callback is called with a Database() object.

Note

In this release, name must be “DB”.

Database objects

class Database()

A Database represents a FoundationDB database — a mutable, lexicographically ordered mapping from binary keys to binary values. Although Database provides convenience methods for reading and writing, modifications to a database are usually via transactions, which are usually created and committed automatically by Database.doTransaction().

Database.doTransaction(func, callback)

Executes the provided function func with a new transaction, commits the transaction, and retries the function as necessary in response to retryable database errors such as transaction conflicts. This is the recommended way to do operations transactionally.

func must take a Transaction() as its first argument and a callback as its second argument.

If any FoundationDB API functions encounter an error inside of func, the error must be passed to callback as its first argument for retry logic to work. If no errors are encountered, then the result of func should be passed to callback as the second argument.

When finished, the callback is called with the result provided by func.

Note

In some failure scenarios, it is possible that your transaction will be executed twice. See Transactions with unknown results for more information.

For example, if db is a Database(), the following call:

db.doTransaction(function(tr, callback) {
    tr.get('a', function(err, val) {

        //Errors must be passed back to the callback for retry logic to work!
        if(err) return callback(err);

        tr.set('b', val);
        callback(null, val);
    });
}, function(err, val) {
    if(err)
        console.log('transaction failed: ', err)
    else
        console.log('finished transaction: ', val);
});

will get the value at key ‘a’ and set it at key ‘b’ in the database. Once the transaction has committed, it will print ‘finished transaction: <value>’.

Functions can be made to automatically invoke doTransaction by using the fdb.transactional() function.

Database.createTransaction()

Returns a new Transaction() object. Consider using the Database.doTransaction() or fdb.transactional() functions to create transactions instead, since they will automatically provide you with appropriate retry behavior.

Throws an error if the transaction could not be created.

Database.get(key, callback)

Gets a value associated with the specified key in the database. This operation will be executed in a Database.doTransaction() error retry loop.

When finished, the callback is called with a Buffer containing the requested value or null if the key does not exist.

Database.getKey(keySelector, callback)

Gets the key referenced by the specified KeySelector(). This operation will be executed in a Database.doTransaction() error retry loop.

When finished, the callback is called with a Buffer containing the requested key.

Database.getRange(start, end, options, callback)

Gets all keys k such that begin <= k < end, and their associated values, as an array of Key-value pairs. This operation will be executed in a Database.doTransaction() error retry loop.

Each of begin and end may be a key or a KeySelector().

If the options object is specified, it can have the following optional parameters:

options.limit
Only the first limit keys (and their values) in the range will be returned. If unspecified, defaults to having no limit.
options.reverse
If true, then the keys in the range will be returned in reverse order. If unspecified, defaults to false.
options.streamingMode
A value from fdb.streamingMode which provides a hint to FoundationDB about how to retrieve the specified range. This option should generally not be specified, allowing FoundationDB to retrieve the full range very efficiently.

When finished, the callback is called with an array containing the requested Key-value pairs.

Database.getRangeStartsWith(prefix, options, callback)

Gets all keys k such that k begins with keyPrefix, and their associated values, as an array of Key-value pairs. This operation will be executed in a Database.doTransaction() error retry loop.

If the options object is specified, it can have the following optional parameters:

options.limit
Only the first limit keys (and their values) in the range will be returned. If unspecified, defaults to having no limit.
options.reverse
If true, then the keys in the range will be returned in reverse order. If unspecified, defaults to false.
options.streamingMode
A value from fdb.streamingMode which provides a hint to FoundationDB about how to retrieve the specified range. This option should generally not be specified, allowing FoundationDB to retrieve the full range very efficiently.

When finished, the callback is called with an array containing the requested Key-value pairs.

Database.set(key, value, callback)

Associates the given key and value and commits the result. Overwrites any prior value associated with key. This operation will be executed in a Database.doTransaction() error retry loop.

callback will be called once the transaction has been committed.

Database.clear(key, callback)

Removes the specified key (and any associated value) if it exists and commits the result. This operation will be executed in a Database.doTransaction() error retry loop.

callback will be called once the transaction has been committed.

Database.clearRange(start, end, callback)

Removes all keys k such that begin <= k < end, and their associated values, and commits the result. This operation will be executed in a Database.doTransaction() error retry loop.

Note

Unlike in the case of Database.getRange(), begin and end must be keys, not KeySelector()s.

callback will be called once the transaction has been committed.

Database.clearRangeStartsWith(prefix, callback)

Removes all the keys k such that k begins with keyPrefix, and their associated values, and commits the result. This operation will be executed in a Database.doTransaction() error retry loop.

callback will be called once the transaction has been committed.

Transactional decoration

fdb.transactional(func)

The fdb.transactional decorator function is a convenience designed to concisely wrap a function with logic to automatically create a transaction and retry until success.

For example:

//Gets the value at key1 and sets it at key2. Returns the value that was set
var simpleFunction = function(tr, key1, key2, callback) {
    tr.get(key1, function(err, val) {

        //Errors must be passed back to the callback for retry logic to work!
        if(err) return callback(err);

        tr.set(key2, val);
        callback(null, val);
    });
};
simplefunction = fdb.transactional(simpleFunction);

The fdb.transactional function makes simpleFunction a transactional function. All functions decorated by fdb.transactional must take a Transaction() as their first argument and a callback as their last.

If any FoundationDB API functions encounter an error in the wrapped function, the error must be passed to callback as its first argument for retry logic to work. If no errors are encountered, then the result of the function should be passed to callback as the second argument.

A caller of a transactional function can pass a Database() instead of a Transaction() as the first argument. In this case, a Transaction will be created and passed to func when it is called and be committed automatically before returning to the caller. If a retryable error occurs and is passed to the callback, then func will be retried until the transaction successfully commits.

A caller may alternatively pass an actual Transaction() as the first parameter. In this case, the function will not attempt to commit the transaction or to retry errors since that is the responsibility of the caller who owns the transaction. This design allows transactionally decorated functions to be composed freely into larger transactions.

If the callback argument is omitted, then the wrapped function will return a Future.

Note

In some failure scenarios, it is possible that your transaction will be executed twice. See Transactions with unknown results for more information.

Transaction objects

class Transaction()

A Transaction object represents a FoundationDB database transaction. All operations on FoundationDB take place, explicitly or implicitly, through a Transaction.

In FoundationDB, a transaction is a mutable snapshot of a database. All read and write operations on a transaction see and modify an otherwise-unchanging version of the database and only change the underlying database if and when the transaction is committed. Read operations do see the effects of previous write operations on the same transaction. Committing a transaction usually succeeds in the absence of conflicts.

Transactions group operations into a unit with the properties of atomicity, isolation, and durability. Transactions also provide the ability to maintain an application’s invariants or integrity constraints, supporting the property of consistency. Together these properties are known as ACID.

Transactions are also causally consistent: once a transaction has been successfully committed, all subsequently created transactions will see the modifications made by it.

The most convenient way to use transactions is to use either the Database.doTransaction() function or the fdb.transactional() decorator function.

Reading data

Transaction.get(key, callback)

Gets a value associated with the specified key in the database.

When finished, the callback is called with a Buffer containing the requested value or null if the key does not exist.

Transaction.getKey(keySelector, callback)

Gets the key referenced by the specified KeySelector().

When finished, the callback is called with a Buffer containing the requested key.

Transaction.getRange(begin, end[, options])

Returns all keys k such that begin <= k < end, and their associated values, as a RangeIterator().

Each of begin and end may be a key or a KeySelector().

If the options object is specified, it can have the following optional parameters:

options.limit
Only the first limit keys (and their values) in the range will be returned. If unspecified, defaults to having no limit.
options.reverse
If true, then the keys in the range will be returned in reverse order. If unspecified, defaults to false.
options.streamingMode
A value from fdb.streamingMode which provides a hint to FoundationDB about how the returned iterator is likely to be used. If unspecified, defaults to fdb.streamingMode.iterator.
Transaction.getRangeStartsWith(keyPrefix[, options])

Returns all keys k such that k begins with keyPrefix, and their associated values, as a RangeIterator().

If the options object is specified, it can have the following optional parameters:

options.limit
Only the first limit keys (and their values) in the range will be returned. If unspecified, defaults to having no limit.
options.reverse
If true, then the keys in the range will be returned in reverse order. If unspecified, defaults to false.
options.streamingMode
A value from fdb.streamingMode which provides a hint to FoundationDB about how the returned iterator is likely to be used. If unspecified, defaults to fdb.streamingMode.iterator.

Snapshot reads

Transaction.snapshot

Snapshot reads selectively relax FoundationDB’s isolation property, reducing Transaction conflicts but making reasoning about concurrency harder.

By default, FoundationDB transactions guarantee serializable isolation, which means that it is as if transactions were executed one at a time, even in the presence of concurrency. Serializability has little performance cost when there are few Transaction conflicts but can be expensive when there are many. FoundationDB therefore also permits individual reads within a transaction to be done as “snapshot” reads.

Snapshot reads differ from ordinary (serializable) reads in two ways. First, snapshot reads permit the values they read to be modified by concurrent transactions, whereas serializable reads cause conflicts in that case. Second, though snapshot and serializable reads in a transaction initially read from the same consistent snapshot of the database, serializable reads see the effects of prior writes in the same transaction and snapshot reads do not. For more information about how to use snapshot reads correctly, see Using snapshot reads.

Lastly, snapshot reads interact with transaction commit a little differently than normal reads. If a snapshot read is outstanding when transaction commit is called that read will immediately return an error. (Normally, transaction commit will wait until outstanding reads return before committing.)

Transaction.snapshot.get(key, callback)

Like Transaction.get(), but as a snapshot read.

Transaction.snapshot.getKey(keySelector, callback)

Like Transaction.getKey(), but as a snapshot read.

Transaction.snapshot.getRange(begin, end[, limit, reverse, streamingMode])

Like Transaction.getRange(), but as a snapshot read.

Transaction.snapshot.getRangeStartsWith(keyPrefix[, limit, reverse, streamingMode])

Like Transaction.getRangeStartsWith(), but as a snapshot read.

Transaction.snapshot.getReadVersion(callback)

Identical to Transaction.getReadVersion() (since snapshot and serializable reads use the same read version).

Writing Data

Transaction.set(key, value)

Associates the given key and value. Overwrites any prior value associated with key. Returns immediately, having modified the snapshot represented by this Transaction.

Transaction.clear(key)

Removes the specified key (and any associated value), if it exists. Returns immediately, having modified the snapshot represented by this Transaction.

Transaction.clearRange(begin, end)

Removes all keys k such that begin <= k < end, and their associated values. Returns immediately, having modified the snapshot represented by this Transaction.

Note

Unlike in the case of Transaction.getRange(), begin and end must be keys, not KeySelector()s. (Resolving arbitrary key selectors would prevent this method from returning immediately, introducing concurrency issues.)

Transaction.clearRangeStartsWith(prefix)

Removes all the keys k such that k begins with keyPrefix, and their associated values. Returns immediately, having modified the snapshot represented by this transaction.

Committing

fdb.transactional(func)

The fdb.transactional decorator function makes it easy to write transactional functions which automatically commit. See fdb.transactional() for explanation and examples.

Database.doTransaction()

Database.doTransaction makes it easy to write transactional functions which automatically commit. See Database.doTransaction() for explanation and examples.

Transaction.commit()

Attempt to commit the changes made in the transaction to the database.

When finished, the callback is called with no result on success, and an error on failure

As with other client/server databases, in some failure scenarios a client may be unable to determine whether a transaction succeeded. In these cases, Transaction.commit() will respond with a commit_unknown_result error. The Transaction.onError() function treats this error as retryable, so retry loops that don’t check for commit_unknown_result could execute the transaction twice. In these cases, you must consider the idempotence of the transaction. For more information, see Transactions with unknown results.

Normally, commit will wait for outstanding reads to return. However, if those reads were snapshot reads or the transaction option for disabling “read-your-writes” has been invoked, any outstanding reads will immediately return errors.

Note

Consider using either the fdb.transactional() decorator function or the Database.doTransaction() function, which not only call Database.createTransaction() and Transaction.commit() for you but also implement the required error handling and retry logic for transactions.

Transaction.onError(error, callback)

Find out whether an error returned by a method of Transaction is a retryable database error. If so, onError will delay as necessary to implement an efficient backoff, and Transaction.reset() the transaction.

If the error was retryable, then the callback will be called with no result. Otherwise, it will be called with the original error.

Note

Consider using either the fdb.transactional() decorator function or the Database.doTransaction() function, which call this method for you.

Transaction.reset()

Rollback a transaction, mostly resetting it to its initial state. The only state that persists through a transaction reset is that which is related to the backoff logic used by Transaction.onError().

Versions

Most applications should use the read version that FoundationDB determines automatically during the transaction’s first read and ignore all of these methods.

Transaction.setReadVersion(version)

Infrequently used. Sets the database version that the transaction will read from the database. The database cannot guarantee causal consistency if this method is used (the transaction’s reads will be causally consistent only if the provided read version has that property).

Transaction.getReadVersion(callback)

Infrequently used. When finished, the callback is called with the transaction’s read version.

Transaction.getCommittedVersion()

Infrequently used. May be called after Transaction.commit() to find the database version at which the transaction was committed.

Throws an error if there is no committed version.

Transaction options

Transaction.options

Transaction options alter the default behavior of FoundationDB transactions. FoundationDB defaults to extremely safe transaction behavior, and we have worked hard to make performance excellent in this default safe mode, so you should not often need to use transaction options.

Transaction.options.setPriorityBatch()

This transaction should be treated as low priority (other transactions should be processed first). Useful for doing potentially saturating batch work without interfering with the latency of other operations.

Transaction.options.setPrioritySystemImmediate()

This transaction should be treated as extremely high priority, taking priority over other transactions and bypassing controls on transaction queuing.

Warning

This is intended for the use of internal database functions and low-level tools; use by applications may result in severe database performance or availability problems.

Transaction.options.setCausalReadRisky()

This transaction does not require the strict causal consistency guarantee that FoundationDB provides by default. The read version of the transaction will be a committed version, and usually will be the latest committed, but it might be an older version in the event of a fault or network partition.

Transaction.options.setCausalWriteRisky()

The application either knows that this transaction will be self-conflicting (at least one read overlaps at least one set or clear), or is willing to accept a small risk that the transaction could be committed a second time after its commit apparently succeeds. This option provides a small performance benefit.

Transaction.options.setReadYourWritesDisable()

When this option is invoked, a read performed by a transaction will not see any prior mutations that occured in that transaction, instead seeing the value which was in the database at the transaction’s read version. This option may provide a small performance benefit for the client, but also disables a number of client-side optimizations which are beneficial for transactions which tend to read and write the same keys within a single transaction. Also note that with this option invoked any outstanding reads will return errors when transaction commit is called (rather than the normal behavior of commit waiting for outstanding reads to complete).

Note

It is an error to set this option after performing any reads or writes on the transaction.

Transaction.options.setReadAheadDisable()

Disables read-ahead caching for range reads. Under normal operation, a transaction will read extra rows from the database into cache if range reads are used to page through a series of data one row at a time (i.e. if a range read with a one row limit is followed by another one row range read starting immediately after the result of the first).

Transaction.options.setAccessSystemKeys()

Allows this transaction to read and modify system keys (those that start with the byte 0xFF).

Transaction.options.setDurabilityDevNullIsWebScale()

This option has no effect yet, but may make users migrating from MongoDB more comfortable.

Buffer conversion

FoundationDB uses Node.js Buffers for all keys and values. The fdb.buffer functions provide some utilities for converting other data types to and from Node.js Buffers.

fdb.buffer(obj)

Converts obj to a Node.js Buffer, assuming it is of an appropriate type. This is called automatically for any key or value passed to the Transaction() functions. The supported types are:

  • Buffer - obj is returned unchanged
  • ArrayBuffer - obj is copied to a new Buffer
  • Uint8Array - obj is copied to a new Buffer
  • string - obj is encoded using UTF-8 and returned as a Buffer
fdb.buffer.fromByteLiteral(str)

Attempts to interpret the string str as a byte-literal string by converting each character to its one-byte character code using str.charCodeAt(). Returns the result as a Node.js Buffer.

Throws an error if str contains any multi-byte characters.

Note

This should not be used for encoding unicode strings. Instead, use new Buffer(str) or consider using the fdb.tuple layer.

fdb.buffer.toByteLiteral(buffer)

Converts a Node.js Buffer to a byte-literal string by converting each byte to a character using String.fromCharCode().

Note

This should not be used for decoding unicode strings. Instead, use buffer.toString() or consider using the fdb.tuple layer.

Key and value data types

Keys and values in FoundationDB are byte arrays stored in Node.js Buffers. As a convenience, functions which take keys and values as arguments can also accept JavaScript strings, which will be encoded using the UTF-8 encoding, or ArrayBuffers. The fdb module also provides some convenience methods for converting to and from Buffers in fdb.buffer. To encode other data types, see the fdb.tuple module and Encoding data types.

Key selectors

FoundationDB’s lexicographically ordered data model permits finding keys based on their order (for example, finding the first key in the database greater than a given key). Key selectors represent a description of a key in the database that could be resolved to an actual key by Transaction.getKey() or used directly as the beginning or end of a range in Transaction.getRange().

For more about how key selectors work, see Key selectors.

class fdb.KeySelector(key, orEqual, offset)

Creates a key selector with the given reference key, equality flag, and offset. It is usually more convenient to obtain a key selector with one of the following methods:

fdb.KeySelector.lastLessThan(key)

Returns a key selector referencing the last (greatest) key in the database less than the specified key.

fdb.KeySelector.lastLessOrEqual(key)

Returns a key selector referencing the last (greatest) key less than or equal to the specified key.

fdb.KeySelector.firstGreaterThan(key)

Returns a key selector referencing the first (least) key greater than the specified key.

fdb.KeySelector.firstGreaterOrEqual(key)

Returns a key selector referencing the first key greater than or equal to the specified key.

KeySelector objects have the following members:

KeySelector.next()

Returns a key selector referencing the key after the one referenced by this key selector.

KeySelector.prev()

Returns a key selector referencing the key before the one referenced by this key selector.

KeySelector.add(addOffset)

Returns a key selector referencing the key with offset addOffset relative to this one.

Callbacks

Many functions in the FoundationDB API are asynchronous and take as their final parameter a callback which is called when the function has completed. Unless otherwise stated, these callbacks will always have the following signature:

callback = function(error, result) { }

If error is null or undefined, then the function succeeded, and the result it returned (if any) is provided in the second argument.

Streamline

The FoundationDB Node bindings also support use of the streamline module for simplified asynchronous development. If using the streamline module, any function which takes a callback may also take an _ to execute the function in a blocking manner:

var db = fdb.open(null, null, _); //This blocks until completed

var x = db.get('x', _); //Blocks until finished
var y = db.get('y', _); //Blocks until finished

Futures

All FoundationDB API functions which take a callback can alternatively return a “future” object if no callback function is passed to them. The result of the operation can be retrieved by passing a callback to the future object. This makes it possible to start multiple operations before waiting for the result. For example:

var x = db.get('x')
var y = db.get('y')

x(function(err, res) {
    y(function(err, res) {
        console.log('finished parallel get', x, y);
    });
});

Futures can also be combined with Streamline:

var x = db.get('x');
var y = db.get('x');

//This blocks until both gets have completed
console.log(x(_) + y(_));

Range iterators

class RangeIterator()

Transaction.getRange() and similar interfaces all return RangeIterator objects. A RangeIterator intelligently manages fetching the range in batches as you iterate so that you can avoid receiving more data than you need (see fdb.streamingMode for more information).

Most of the functions in RangeIterator (excluding RangeIterator.next()) restart iteration from the beginning of the results, even if the iterator has been used before or is being used concurrently.

Key-value pairs

Each of the RangeIterator functions returns results as key-value pair objects of the form:

var kvPair = {
    key: new Buffer(''),   // A Buffer containing the key
    value: new Buffer('')  // A Buffer containing the value
};
RangeIterator.forEach(func, callback)

Iterates over the requested range by calling func for each key-value pair fetched from the database.

The func function will be passed a key-value pair containing the next result matching the range criteria as its first argument and a callback as its second. func must call its callback upon completion. If its callback is called with an error or defined result, then iteration will terminate immediately.

When either all results matching the range criteria have been exhausted or func terminates prematurely, then callback is called with the result returned through func‘s callback, if any.

For example, the following usage will print the first 10 keys and values in the range [‘apple’, ‘cherry’):

var numKeys = 0;
var itr = tr.getRange('apple', 'cherry');
itr.forEach(function(kv, cb) {
    console.log(kv.key, kv.value);

    if(++numKeys === 10)
        cb(null, null);
    else
        cb();
}, function(err, res) {
    console.log('Finished forEach', err, res);
}
RangeIterator.forEachBatch(func, callback)

Iterates over the requested range by calling func for each batch of key-value pairs fetched from the database. The size of batches is determined by which fdb.streamingMode is used.

The func function will be passed an array of key-value pairs containing the current batch of range results as its first argument and a callback as its second. func must call its callback upon completion. If its callback is called with an error or defined result, then iteration will terminate immediately.

When either all results matching the range criteria have been exhausted or func terminates prematurely, then callback is called with the result returned through func‘s callback, if any.

For example, the following usage will print the first 10 keys and values in the range [‘apple’, ‘cherry’):

var numKeys = 0;
var itr = tr.getRange('apple', 'cherry');
itr.forEachBatch(function(arr, cb) {
    for(var i in arr) {
        console.log(arr[i].key, arr[i].value);
        if(++numKeys === 10) {
            cb(null, null);
            return;
        }
    }

    cb();
}, function(err, res) {
    console.log('Finished forEachBatch', err, res);
}
RangeIterator.toArray(callback)

Converts the requested range to an array of key-value pairs. Unless you intend to use the entire range result, it may be more efficient to use one of RangeIterator.forEachBatch() or RangeIterator.forEach().

When finished, the callback is called with an array containing all key-value pairs matching the range criteria.

For example, the following usage will print all keys and values in the range [‘apple’, ‘cherry’):

tr.getRange('apple', 'cherry').toArray(function(err, kvArr) {
    if(err)
        console.log('Error:', err);
    else
        for(var i in kvArr)
            console.log(kvArr[i].key, kvArr[i].value);
};
RangeIterator.next(callback)

Gets the next item in the range as a key-value pair. It is generally easier to use one of RangeIterator.forEachBatch(), RangeIterator.forEach(), or RangeIterator.toArray().

When finished, the callback is called with the next key-value pair in the range. If there are no more pairs matching the range criteria, then null is returned.

Streaming modes

fdb.streamingMode

When using Transaction.getRange() and similar interfaces, API clients can request large ranges of the database to iterate over. Making such a request doesn’t necessarily mean that the client will consume all of the data in the range - sometimes the client doesn’t know how far it intends to iterate in advance. FoundationDB tries to balance latency and bandwidth by requesting data for iteration in batches.

Streaming modes permit the API client to customize this performance tradeoff by providing extra information about how the iterator will be used.

The following streaming modes are available:

fdb.streamingMode.iterator

The default. The client doesn’t know how much of the range it is likely to use and wants different performance concerns to be balanced.

Only a small portion of data is transferred to the client initially (in order to minimize costs if the client doesn’t read the entire range), and as the caller iterates over more items in the range larger batches will be transferred in order to maximize throughput.

fdb.streamingMode.want_all

The client intends to consume the entire range and would like it all transferred as early as possible.

fdb.streamingMode.small

Infrequently used. Transfer data in batches small enough to not be much more expensive than reading individual rows, to minimize cost if iteration stops early.

fdb.streamingMode.medium

Infrequently used. Transfer data in batches sized in between small and large.

fdb.streamingMode.large

Infrequently used. Transfer data in batches large enough to be, in a high-concurrency environment, nearly as efficient as possible. If the client stops iteration early, some disk and network bandwidth may be wasted. The batch size may still be too small to allow a single client to get high throughput from the database, so if that is what you need consider fdb.streamingMode.serial.

fdb.streamingMode.serial

Transfer data in batches large enough that an individual client can get reasonable read bandwidth from the database. If the client stops iteration early, considerable disk and network bandwidth may be wasted.

fdb.streamingMode.exact

Infrequently used. The client has passed a specific row limit and wants that many rows delivered in a single batch. This is not particularly useful in Node.js because iterator functionality makes batches of data transparent, so use fdb.streamingMode.want_all instead.

Tuple layer

fdb.tuple

The FoundationDB API comes with a built-in layer for encoding tuples into keys usable by FoundationDB. The encoded key maintains the same sort order as the original tuple: sorted first by the first element, then by the second element, etc. This makes the tuple layer ideal for building a variety of higher-level data models.

Tuple Data Types

A Node.js tuple is an array that can contain any combination of the following data types:

Type Legal Values
Null value null
Byte string Any value of type Buffer, ArrayBuffer, or Uint8Array
Unicode string Any value of type String
54-bit signed integer number in the range [-253, 253) that has no fractional part

If T is a JavaScript array meeting these criteria, then:

T == fdb.tuple.unpack(fdb.tuple.pack(T))

Warning

In general, FoundationDB tuples can contain 64-bit integers. Node.js, however, lacks an appropriate data type to handle integers of that size accurately. If you intend to use the Node.js bindings with other language bindings, keep in mind that attempting to decode a tuple with signed integers larger than 54 bits will result in an error being thrown.

fdb.tuple.pack(tuple)

Returns a key (Buffer) encoding the specified array tuple

Throws an error if tuple contains any elements that are not one of the encodable data types.

fdb.tuple.unpack(key)

Returns the tuple encoded by the given key as an array

Throws an error if the unpacked tuple contains any integers outside the range of a 54-bit signed integer.
Throws an error if the encoded tuple contains unknown data types.
fdb.tuple.range(tuple)

Returns the range containing all keys that encode tuples strictly starting with the array tuple (that is, all tuples of greater length than tuple of which tuple is a prefix).

The range will be an object of the form:

var range = {
    begin: new Buffer(''), // A Buffer containing the beginning of the range, inclusive
    end: new Buffer('')    // A Buffer containing the end of the range, exclusive
};

This range can be used to call Transaction.getRange(). For example:

var r = fdb.tuple.range(['A', 2]);
var itr = tr.get(r.begin, r.end);

returns a RangeIterator() over all key-value pairs in the database whose keys would unpack to tuples like (‘A’, 2, x), (‘A’, 2, x, y), etc.

Throws an error if tuple contains any elements that are not one of the encodable data types.