Incompatible API changes
[5.12.1]
Client no longer supports Node.js version 21
[5.9.0]
Client no longer supports Red Hat Enterprise Linux 7
Client no longer supports Amazon Linux 2
Client no longer supports Oracle Linux 7
Client no longer supports CentOS 7
Client no longer supports Debian 10
Client no longer supports macOS 11
[5.8.0]
Client no longer supports Node.js 19
Client no longer supports Node.js 16
[5.5.0]
Client no longer supports Node.js 14
[5.4.0]
Client no longer supports Ubuntu 18.04
Client no longer supports Debian 10 on ARM64 architecture
[5.2.0]
Client does not support Node.js LTS version 14 on macOS using ARM architecture
[5.0.0]
Predicate Expression Filter Replaced by New Filter Expressions
- Usage
- New Filter Expressions
const query = client.query(helper.namespace, helper.set)const queryPolicy = { filterExpression: exp.eq(exp.binInt('a'), exp.int(9))}const stream = query.foreach(queryPolicy)
- Deprecated PredicateExpression Filter
const query = client.query(helper.namespace, helper.set)
- New Filter Expressions
[4.0.0]
totalTimeout Replaced by timeout Info Policy Option
- Usage
-
New “timeout” InfoPolicy
const subject = new Aerospike.InfoPolicy({timeout: 1000,sendAsIs: true,checkBounds: false}) -
Deprecated “totalTimeout” InfoPolicy
const subject = new Aerospike.InfoPolicy({totalTimeout: 1000,sendAsIs: true,checkBounds: false})
-
Version 3.16.0
Percent-Based Sampling Replaced by Max-Records Scan Policy Option
Aerospike server version 4.9 and Node.js client version 3.16 support a new
maxRecords
scan policy option which limits the number of records the server
nodes will return to the client when performing a scan operation. This can be
used to perform a random sample of a given namespace/set in the database.
With the introduction of the maxRecords
scan policy, the percent
scan
option has been deprecated. The v3.16.0 client continues to support the
percent
scan options on server versions older than 4.9, but for server
versions 4.9 and newer, the client no longer sends the percent
option for
scan operations if specified as part of the scan command. Please use the new
maxRecords
scan policy option instead on server versions 4.9 and newer.
Update: This breaking change was reversed in version 3.16.2. The old
percent
scan option can also be used with server version 4.9 and later.
However, note that scan percent and max_records
are mutually exclusive; the
client will return an error if both values are set on a scan policy.
Usage
New max records scan policy:
const scanPolicy = new Aerospike.ScanPolicy({ maxRecords: 1000 // return approx. 1,000 records})const scan = client.scan(namespace, set)const stream = scan.foreach(scanPolicy)
Deprecated percent scan option:
const scanOptions = { percent: 10 // return approx. 10% of all records}const scan = client.scan(namespace, set, scanOptions)const stream = scan.foreach()
Version 3.10.0
Read Consistency Level Changes
Read policy changes for commands involving AP (availability) namespaces
- Policy variable
consistencyLevel
was replaced byreadModeAP
for the read, batch and, operate policies. - In the
Aerospike.policy
module the following enum values were replaced:consistencyLevel.ONE
was replaced byreadModeAP.ONE
consistencyLevel.ALL
was replaced byreadModeAP.ALL
Read policy changes for commands involving SC (strong consistency) namespaces
- Policy variable
linearizeRead
was replaced byreadModeSC
for the read, batch, and operate policies. - Added
Aerospike.policy.readModeSC
enum - see API docs for details.
Version 3.8.0
Shared Memory Layout & Key Changes
Shared memory layout has changed. If you are using shared memory clients, it is critical to change the (shared memory key) when upgrading from Node.js client to v3.8.0. The default value for the key has changed from 0xA7000000 to 0xA8000000.
Please refer to the Shared Memory section in the Aerospike C Client’s documentation for more information about the client’s usage of shared memory.
Version 3.0.0
Removal of LargeList (LDT) Functionality
The Client#LargeList
function and all related functionality supporting Large Data Types (LDT) have been removed. Deprecation of LDT was first announced on the Aerospike Blog in November 2016. Aerospike Server v3.14 is the last server release to support LDT functionality.
Promise-based API & Changes in Callback Method Signatures
In addition to callback functions, the v3 client also supports an async API
based on Promises. (And async
/await
when using Node.js v8 or later!) The callback function parameter on all async client commands
is now optional. If no callback function is passed, the command will return a
Promise instead. A Promise
object represents the eventual completion (or failure) of an asynchronous
operation, and its resulting value.
In contrast to callback functions, a Promise can only resolve to a single
result value. In v2, several of the client’s callback functions passed more
than one result value. For example, the record callback
function used by the v2 Client#get
command, passes the record bins, meta
data and the keys in three separate parameters to the callback function: recordCallback(error, bin, meta, key)
.
To harmonize the result values passed to callback functions and the values returned by Promises, all client commands in v3 return a single result value. The method signatures of several callback functions have been updated to combine multiple separate result values into a single result object.
Callback | v2 / v3 Method Signature | Affected Client Commands |
---|---|---|
Record Callback | v2: cb(error, bins, meta, key) v3: cb(error, record) | Client#get , Client#operate , Client#append , Client#prepend , Client#add , Client#select |
Batch Record Callback | v2: cb(error, [{status:, key:, bins:, meta:}]) v3: cb(error, [{status:, record:}]) | Client#batchRead , Client#batchGet , Client#batchSelect |
Record Stream data Event Callback | v2: cb(bins, meta, key) v3: cb(record) | Query#foreach , Scan#foreach |
Note: The record
object passed in v3 is an instance of the new Record
class, which contains the records bins, key and meta-data.
Update Error Status Codes & Messages
The constants for the error status codes in the Aerospike.status
module have
been renamed to drop the redundant AEROSPIKE_
prefix. For example:
Aerospike.status.AEROSPIKE_OK
→Aerospike.status.OK
Aerospike.status.AEROSPIKE_ERR_RECORD_NOT_FOUND
→Aerospike.status.ERR_RECORD_NOT_FOUND
Aerospike.status.AEROSPIKE_ERR_NO_MORE_CONNECTIONS
→Aerospike.status.ERR_NO_MORE_CONNECTIONS
- …
The old contents (with AEROSPIKE_
prefix) still exist for now, but are
undocumented; they will be removed in the next major client version.
AerospikeError
instances now also have proper, human readable error messages in most cases.
Policy Changes, Improved Timeout & Retry Handling
The v3 client provides separate ES6 classes for all client command
policies, such as Aerospike.ReadPolicy
or Aerospike.WritePolicy
. Passing
policy values as plain objects to client commands is still supported but may be
deprecated at some point in the future. The policy classes provide
additional functionality, like validation and support for handling future and backward
incompatible policy changes. We recommend you start using
the new policy classes over plain objects.
You can set global default policies when creating a new client instance. You must set default policies separately for all command types, such as read, write, and operate. Setting global default policy values that apply to all command policies is no longer supported.
All client command policies, except InfoPolicy
and MapPolicy
, are based on a new BasePolicy
class that
encodes some important differences in how the v3 client handles timeouts and automatic retries.
The timeout
policy value of the v2 client has been renamed to totalTimeout
and specifies the total command timeout in milliseconds. The totalTimeout
is tracked on the client and sent to the server along with the command in
the wire protocol. The client will most likely timeout first, but the server
also has the capability to timeout the command. If totalTimeout
is not
zero and totalTimeout
is reached before the command completes, the
command will return error ERR_TIMEOUT
. If totalTimeout
is zero, there
will be no total time limit. The default value for totalTimeout
is 1,000 milliseconds.
The new socketTimeout
policy value specifies the socket idle timeout in
milliseconds. If socketTimeout
is not zero and the socket has been idle for
at least socketTimeout
, both maxRetries
and totalTimeout
are checked. If
maxRetries
and totalTimeout
are not exceeded, the command is retried.
The default value for socketTimeout
is zero, meaning no socket idle time limit.
maxRetries
is used to specify the maximum number of retries before aborting
the current command. The default value for maxRetries
is 2. The initial
attempt is not counted as a retry. If maxRetries
is exceeded, the command
will return error ERR_TIMEOUT
.
WARNING: Database writes that are not idempotent (such as Client#incr
) should not be
retried because the write operation may be performed multiple times if the
client timed out previous command attempts. It is important to use a
distinct WritePolicy
for non-idempotent writes which sets maxRetries
to
zero.
Example: Using the new policy classes to specify timeout and retry handling:
const Aerospike = require('aerospike')
let defaults = { socketTimeout: 200, totalTimeout: 500, maxRetries: 2}let config = { policies: { read: new Aerospike.ReadPolicy(defaults), write: new Aerospike.WritePolicy(defaults) // timeout: 500 - Can no longer specify global defaults here! }}
let key = new Aerospike.Key('test', 'demo', 'k1')
Aerospike.connect(config) .then(client => { return client.put(key, {value: 10}) .then(() => { let policy = new Aerospike.OperatePolicy({ maxRetries: 0 }) return client.incr(key, {value: 20}, {}, policy) }) .then(() => client.get(key)) .then(record => console.info('Value:', record.bins.value)) .then(() => client.close()) .catch(error => { client.close() return Promise.reject(error) }) }) .catch(error => console.error('Error:', error))
Changed Semantics of Client#exists
Command
The Client#exists
command now returns a simple boolean value to indicate
whether a record exists in the database under the given key. It is no longer
necessary, nor possible, to check the commands’s status code for the
ERR_RECORD_NOT_FOUND
error.
Usage under v2:
let key = new Aerospike.Key('test', 'test', 'noSuchKey')client.exists(key, error => { if (error && error.code !== Aerospike.status.ERR_RECORD_NOT_FOUND) { // An error occurred while executing the command. } else if (error) { // The record does not exist. } else { // The record for the key exists. }})
Usage under v3:
let key = new Aerospike.Key('test', 'test', 'noSuchKey')client.exists(key, (error, result) => { if (error) { // An error occurred while executing the command. } else if (result) { // The record for the key exists. } else { // The record does not exist. }})
Changed Semantics of Client#createIndex
and Client#indexRemove
Commands
The Client#createIndex
command now returns an error with status code
ERR_INDEX_FOUND
if an index with the same name already exists and/or if an
index of any name already exists on the same bin.
The Client#removeIndex
command now returns an error with status code
ERR_INDEX_NOT_FOUND
if no index with the given name exists in the cluster.
Shared Memory Layout & Key Changes
Shared memory layout has changed. If you are using shared memory clients, it is
critical to change the shared memory key (Config#sharedMemory.key
) when
upgrading from Node.js client v2 to v3. The default value for the key has
changed from 0xA6000000 to 0xA7000000.
Please refer to the Shared Memory section in the Aerospike C Client’s documentation for more information about the client’s usage of shared memory.
Removal of Client Functions Deprecated under v2
The following Client functions have been marked as deprecated under v2.x and have been removed in v3:
Removed Function | Replacement | Remarks |
---|---|---|
Aerospike.Double() | new Aerospike.Double() | - |
Aerospike.filter.geoContains() | Aerospike.filter.geoContainsGeoJSONPoint() | - |
Aerospike.filter.geoWithin() | Aerospike.filter.geoWithinGeoJSONRegion() | - |
Aerospike.indexType.<STRING, NUMERIC, GEO2DSPHERE> | Aerospike.indexDataType.<STRING, NUMERIC, GEO2DSPHERE> | - |
Aerospike.info.parseInfo() | Aerospike.info.parse() | - |
Aerospike.key() | new Aerospike.Key() | - |
Aerospike.operator.<*> | Aerospike.operations.<*> | - |
Aerospike.operator.list<*> | Aerospike.lists.<*> | - |
Client#LargeList() | - | See “Removal of LDT functionality” |
Client#execute() | Client#apply() | - |
Client#info() w/o host param | Client#infoAll() | - |
Client#udfRegisterWait() | UdfJob#wait() | Client#udfRegister() & Client#udfRemove() return a UdfJob instance. |
Client#createIndexWait() | IndexJob#wait() | Client#createIndex() & Client#create<*>Index() return an IndexJob instance. |
InfoPolicy#send_as_is | InfoPolicy#sendAsIs | - |
InfoPolicy#check_bounds | InfoPolicy#checkBounds | - |
LargeList#* | - | See “Removal of LDT functionality” |
Query#execute() | Query#foreach() | |
Scan#execute() | Scan#foreach() |
Supported Node.js versions
Node.js v0.12 is no longer supported. Node.js v4 (LTS) or later are required to run Aerospike Node.js client v3.0.
Version 2.6.0
Deprecations
Deprecated Function | Replacement | Remarks |
---|---|---|
Info#parseInfo | Info#parse | parse and parseInfo both parse the info data returned by the Aerospike server; there are some minor differences between the parsed data returned by the two functions for some info keys |
Client#udfRegisterWait | UdfJob#waitUntilDone | An UdfJob instance is passed to the client’s udfRegister /udfRemove callback functions. |
Version 2.4.4
Deprecation of LargeList Functionality
Aerospike will no longer support the Large Data Type (LDT) feature so all LargeList related functions have been marked as deprecated. Please refer to this article on the Aerospike company blog for more details.
Deprecations
Deprecated Function | Replacement | Remarks |
---|---|---|
Client#LargeList | - | see above |
LargeList#* | - | see above |
Version 2.4.0
Shared Memory Layout Changes
Multiple client instances running in separate processes on the same machine can use shared memory to share cluster status, including nodes and data partition maps. See sharedMemory config for more information.
In v4.1.0 of the Aerospike C client library, which is included in v2.4.0 of the Aerospike Node.js client, the shared memory layout has changed. The default shm_key config has changed to 0xA6000000 so old client applications do not mix shared memory with new client applications. If you are using shared memory clients with a custom shm_key, it’s critical that this key changes when upgrading to v2.4.0 of the Aerospike Node.js client.
Deprecations
Deprecated Function | Replacement | Remarks |
---|---|---|
InfoPolicy#send_as_is | InfoPolicy#sendAsIs | - |
InfoPolicy#check_bounds | InfoPolicy#checkBounds | - |
ReadPolicy#retry | - | - |
WritePolicy#retry | - | - |
RemovePolicy#retry | - | - |
OperatePolicy#retry | - | - |
Notes:
- The
retry
policy value for read, write, remove and operate policies has not been effective for any single key read/write commands, the batch read command or query/scan commands in client versions v2.x.
Version 2.1.0
New modules for Scalar, List & Map operations
The Aerospike.operator
module has been split into three separate modules for operations on scalar values, lists and maps:
Aerospike.operations
- Operations on scalar values, such as Strings, Integers, and Doubles.Aerospike.lists
- Operations on lists, such as append, insert, and remove.Aerospike.maps
- Operations on sorted maps, such as put, getByKey, and removeByIndex.
The old Aerospike.operator
module has been deprecated and will be removed in the next major release.
Deprecations
Deprecated Function | Replacement | Remarks |
---|---|---|
Aerospike.operator.append | Aerospike.operations.append | - |
Aerospike.operator.incr | Aerospike.operations.incr | - |
Aerospike.operator.prepend | Aerospike.operations.prepend | - |
Aerospike.operator.read | Aerospike.operations.read | - |
Aerospike.operator.touch | Aerospike.operations.touch | - |
Aerospike.operator.write | Aerospike.operations.write | - |
Aerospike.operator.list<*> | Aerospike.lists.<*> | - |
Version 2.0.0
None. But see 2.0.0-alpha.1 through 2.0.0-alpha.3 for list of backward incompatible changes since v1.x.
Version 2.0.0-alpha.3
New Query Interface
The Client API for executing Queries was revised in this release and has several backward incompatible changes.
Processing Query Results
Prior to v2.0.0-alpha.3 the data
event on the RecordStream
interface would
pass a single record object to the event handler function, with two properties
bins
and meta
containing the bin values and the meta data for the
record respectively. Starting with v2.0.0-alpha.3, the data
event instead
pass the bin values and the meta data as two separate parameters into the event
handler. (Same as the Scan interface introduced in v2.0.0-alpha.2.)
Before:
# broken code - do not use in v2 clientvar statement = { 'filters': [...]}var query = client.query('ns', 'set', statement)var stream = query.execute()stream.on('error', function (error) { // handle error})stream.on('data', function (record) { console.log(record.bins) console.log(record.meta)})stream.on('end', function () { // query completed})
After:
var statement = { 'filters': [...]}var query = client.query('ns', 'set', statement)var stream = query.foreach()stream.on('error', function (error) { // handle error})stream.on('data', function (bins, meta) { console.log(bins) console.log(meta)})stream.on('end', function () { // query completed})
Separation of Query and Scan APIs
In Aerospike Node.js client v1.x, both queries (with filter predicates) and
scans (without filter predicates) where handled via the Client#query
command
and the Query#execute
method. In v2.0.0-alpha.2, the new Scan API was
introduced, and scan operations should now be initiated via Client#scan
.
Starting with v2.0.0-alpha.3, the Query API will no longer accept any of the
properties specific to scans in the query statement when calling Client#query
.
Including any of the following five keys will result in an exception being
raised by the client:
UDF
concurrent
percentage
nobins
The concurrent
, percentage
and nobins
values should be set
via the Scan API instead and the Lua UDF parameters for applying a Aerospike
Record UDF on a background scan should be passed directly to Scan#background
.
Before: Executing Background Scan
# broken code - do not use in v2 clientvar statement = { 'UDF': { module: 'myLuaModule', funcname: 'myLuaFunction', args: ['some', 'function', 'arguments'] }}var query = client.query('ns', 'set', statement)var stream = query.execute()stream.on('error', function (error) { // handle error})stream.on('end', function (scanID) { // retrieve scanID, which can be used to check scan job status})
After: Executing Background Scan
var udfArgs = ['some', 'function', 'arguments']var scan = client.scan('ns', 'set')scan.background('myLuaModule', 'myLuaFunction', udfArgs, function (error, scanJob) { if (error) { // handle error } else { // use scanJob.info() and/or scanJob.waitUntilDone() to check scan job status }})
Before: Setting Scan Concurrent Execution
# broken code - do not use in v2 clientvar statement = { concurrent: true, nobins: true, percentage: 50}var query = client.query('ns', 'set', statement)var stream = query.execute()stream.on('error', function (error) { // handle error})stream.on('data', function (record) { // process scan results})stream.on('end', function () { // scan completed})
After: Setting Scan Concurrent Execution
var scan = client.scan('ns', 'test')scan.concurrent = truescan.nobins = truescan.percentage = 50var stream = scan.foreach()stream.on('error', function (error) { // handle error})stream.on('data', function (bins, meta) { // process scan results})stream.on('end', function () { // scan completed})
Query Aggregation using Stream UDFs
Applying a Lua User-Defined Function (UDF) as an Aerospike Stream UDF for query
aggregation is now done via the new Query#apply
function, rather than by
passing the aggregationUDF
parameter in the query statement and calling
Query#execute
. Query#apply
returns the aggregation result via asynchronous
callback so it is no longer necessary to extract the single result value from a
record stream.
Before:
# broken code - do not use in v2 clientvar statement = { aggregationUDF: { module: 'myLuaModule', funcname: 'myLuaFunction', args: ['some', 'function', 'arguments'] }}var query = client.query('ns', 'set', statement)var stream = query.execute()stream.on('error', function (error) { // handle error})stream.on('data', function (result) { // handle result})
After:
var query = client.query('ns', 'set')var udfArgs = ['some', 'function', 'arguments']query.apply('myLuaModule', 'myLuaFunction', udfArgs, function (error, result) { if (error) { // handle error } else { // handle result }})
Deprecations
Deprecated Function | Replacement | Remarks |
---|---|---|
Aerospike#scanStatus | Aerospike#jobStatus | - |
Query#execute | Query#foreach | - |
Scan#execute | Scan#foreach | Scan class was introduced in 2.0.0-alpha.2 |
Scan#selectBins | Scan#select | Scan class was introduced in 2.0.0-alpha.2 |
Version 2.0.0-alpha.2
Deprecations
Deprecated Function | Replacement | Remarks |
---|---|---|
Client#createIndexWait | IndexTask#waitUntilDone | - |
Aerospike.filter.geoWithin | Aerospike.filter.geoWithinGeoJSONRegion | - |
Aerospike.filter.geoContains | Aerospike.filter.geoContainsGeoJSONPoint | - |
When creating new secondary indexes via the Client#createIndex
method,
Client#createIntegerIndex
, or short-hand methods, the optional info policy
should be passed as a separate function parameter instead of passing it in the
first options
parameter. The options.policy
parameter is deprecated.
In the info object returned by Query#info
the recordScanned
property has
been renamed to recordsScanned
. For now the info object will contain the same
value under both the new and old name but the recordScanned
property will be
removed in some future release.
Version 2.0.0-alpha.1
Error-first callbacks
Callbacks no longer return an error object with status code
AEROSPIKE_OK
(0). Instead, if the client command succeeds, the first
argument to the callback (the error
argument) will be null
.
To revert to the previous callback behavior, set the callback handler for the
client to the LegacyCallbackHandler
using the Client.setCallbackHandler
method. You need to set the callback handler before instantiating any client
instances. You can do so, for example, by using the Aerospike.client
or Aerospike.connect
methods:
const Aerospike = require('aerospike')const Client = Aerospike.ClientClient.setCallbackHandler(Client.LegacyCallbackHandler)
Aerospike.connect((error, client) => { console.log(error) => // { code: 0, message: '', func: '', file: '', line: 0 } if (error.code !== Aerospike.status.AEROSPIKE_OK) { // handle error } else { // client instance is ready receive commands client.close() }})
Releasing of event loop resources
To handle asynchronous client commands send to the Aerospike server cluster, the client needs to register an async handle on Node.js event loop. This handle needs to be freed explicitly in order for the event loop to exit and the Node.js application to terminate.
Single Aerospike client instance
When working with a single Aerospike Node.js client instance, you can use the
client’s close
method to close the connection to the server nodes and release
all event loop resources. It is important to call the client’s close
method
as otherwise the application might not terminate.
Example:
const Aerospike = require('aerospike')
Aerospike.connect((error, client) => { if (error) throw error // client instance is ready receive commands client.close()})
Multiple (concurrent) Aerospike client instances
If the application needs to instantiate more than one Aerospike client, such as
when connecting to multiple Aerospike server clusters, then the event loop resources
should only be released after the last client instance was closed. To prevent
automatic release of the event loop resources, the client’s close
method
needs to be called with the releaseEventLoop
parameter set to false:
var releaseEventLoop = falseclient.close(releaseEventLoop)
After the last client instance is closed, the releaseEventLoop
method
on the Aerospike
module needs to be called before the program terminates:
Aerospike.releaseEventLoop()
Example:
const Aerospike = require('aerospike')
// called one or more times to handle a new work requestfunction handleRequest (request) { Aerospike.connect((error, client) => { if (error) throw error // handle request client.close(false) // do not release event loop })}
// called when application shuts downfunction shutdown () { Aerospike.releaseEventLoop()}
Supported Node.js versions
Node.js v0.10 is no longer supported. Node.js v0.12 or later are required to run Aerospike Node.js client v2.0.
Deprecations
The following functions have been deprecated and/or replaced:
Deprecated Function | Replacement | Remarks |
---|---|---|
Aerospike.key | new Aerospike.Key | - |
Aerospike.Double | new Aerospike.Double | - |
Aerospike.GeoJSON | new Aerospike.GeoJSON | - |
Client#batchExists | Client#batchRead | Requires Aerospike server version >= 3.6.0. |
Client#batchGet | Client#batchRead | Requires Aerospike server version >= 3.6.0. |
Client#batchSelect | Client#batchRead | Requires Aerospike server version >= 3.6.0. |
Client#execute | Client#apply | - |
Client#add | Client#incr | - |