Key/Value
The key/value model is the simplest data model: every value is reachable through a single identifier (the key). ArcadeDB supports the key/value pattern natively without sacrificing the richer features of the multi-model engine — values can be primitive types, full documents, or even graph elements.
How Keys Work in ArcadeDB
Every record stored in ArcadeDB is automatically addressable by its Record ID (RID), a compact identifier of the form #bucket:offset.
The RID provides O(1) direct access to any record, which means the entire database functions as a high-performance key/value store — no separate engine, no extra indexes required.
In addition to RIDs, you can layer your own keys on top:
-
Indexed keys — create a unique LSM-Tree index on any property to look up records by an arbitrary identifier such as
userId,sku, oremail. -
Bucket-based keys — group records into buckets and use the bucket as a key/value namespace where records are inserted and retrieved by RID without requiring a type schema.
-
Composite keys — create indexes spanning multiple properties when the natural key is not a single value (for example,
(tenantId, accountId)).
Key/Value with the Redis Wire Protocol
ArcadeDB speaks the Redis wire protocol, so any Redis client (here Jedis) can use it as a drop-in key/value backend.
Simple string commands (SET, GET, INCR, …) operate on a fast in-memory namespace:
final Jedis jedis = new Jedis("localhost", 6379);
jedis.set("foo", "1"); // store
String value = jedis.get("foo"); // read -> "1"
boolean present = jedis.exists("foo"); // check
jedis.incr("foo"); // atomic increment -> 2
jedis.incrBy("foo", 3); // -> 5
String removed = jedis.getDel("foo"); // read + delete atomically
To persist values as queryable documents, back the key with a unique index and use the hash commands.
The HGET/HEXISTS/HDEL key uses the form database.Type[indexName]:
// One-time schema: a type plus a unique index acting as the key
database.command("sqlscript",
"CREATE DOCUMENT TYPE Account;" +
"CREATE PROPERTY Account.id LONG;" +
"CREATE INDEX ON Account (id) UNIQUE;" +
"CREATE PROPERTY Account.email STRING;" +
"CREATE INDEX ON Account (email) UNIQUE;");
// Store a JSON value under the "Account" type
jedis.hset("mydb", "Account", "{'id':1,'email':'jay@commodore.com','firstName':'Jay'}");
// Read it back by the indexed key (id == 1)
JSONObject doc = new JSONObject(jedis.hget("mydb.Account[id]", "1"));
// ...or by the email key
doc = new JSONObject(jedis.hget("mydb.Account[email]", "jay@commodore.com"));
boolean present = jedis.hexists("mydb.Account[id]", "1");
jedis.hdel("mydb.Account[id]", "1"); // delete by key
Records can also be addressed directly by their RID: jedis.hget("mydb", "#13:432").
Key/Value with the Java API
Create a unique index on the property you want to use as the key, then look records up with lookupByKey:
database.command("sql",
"CREATE DOCUMENT TYPE Account;" +
"CREATE PROPERTY Account.id LONG;" +
"CREATE INDEX ON Account (id) UNIQUE");
// Single-key lookup
final IndexCursor result = database.lookupByKey("Account", "id", 12345L);
if (result.hasNext())
Document value = result.next().asDocument();
// Composite-key lookup (e.g. multi-tenant natural keys)
final IndexCursor composite = database.lookupByKey("Account",
new String[] { "tenantId", "accountId" },
new Object[] { "acme", 42L });
For ephemeral, in-memory state (session data, counters) that does not need its own type, use database global variables, which are also readable from SQL:
database.setGlobalVariable("myKey", "myValue");
Object value = database.getGlobalVariable("myKey"); // "myValue"
// SELECT $myKey returns the value from SQL
Key/Value over HTTP
Over the HTTP API, key/value access is expressed as SQL through the /api/v1/command/<database> endpoint.
A lookup by indexed key is a simple parameterized query:
# Read the value whose key id = 1
curl -X POST "http://localhost:2480/api/v1/command/mydb" \
-u root:password -H "Content-Type: application/json" \
-d '{"language":"sql","command":"SELECT FROM Account WHERE id = :id","params":{"id":1}}'
# Store / upsert a value by key
curl -X POST "http://localhost:2480/api/v1/command/mydb" \
-u root:password -H "Content-Type: application/json" \
-d '{"language":"sql","command":"UPDATE Account SET email = :e UPSERT WHERE id = :id","params":{"id":1,"e":"jay@commodore.com"}}'
This makes ArcadeDB usable as a drop-in key/value backend for caches, session stores, configuration stores, or any pattern where direct addressing by identifier is the primary access mode.
Comparison with Other Models
| Relational Model | Key/Value Model | ArcadeDB Key/Value Model |
|---|---|---|
Table |
Bucket |
|
Row |
Key/Value pair |
Document |
Column |
not available |
Document field or Vertex/Edge property |
Relationship |
not available |
Why ArcadeDB for Key/Value
Most key/value stores treat the value as opaque — a blob of bytes the database doesn’t understand. ArcadeDB treats every value as a structured record:
-
Rich values — values can be documents, vertices, or edges with typed properties, not just byte arrays.
-
Queryable — the same record retrievable by RID is also queryable with SQL, Cypher, Gremlin, and other languages, without re-indexing or duplicating data.
-
Transactional — key/value writes participate in full ACID transactions alongside graph and document operations.
-
Persistent — LSM-Tree storage with automatic compaction ensures durability and efficient disk usage at scale.
-
Multi-protocol — access the same data through HTTP, the Redis wire protocol, the Java API, or any other supported interface.
Further Reading
-
Record ID (RID) — how RIDs work and how to use them as primary keys
-
Buckets — physical storage units that double as key/value namespaces
-
HTTP API — run SQL commands and queries (including key lookups) over REST
-
Redis Wire Protocol — speak the Redis protocol against ArcadeDB