
---
title: "Aerospike Interactive Tutorial: Basic Operations"
description: "Master Aerospike CRUD operations with this interactive Python tutorial covering put, get, remove, and operate APIs."
---

# Basic Operations

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

::: note
**A note on terminology:**

-   An **operation** is a discrete action on the contents of a [bin](https://aerospike.com/docs/database/learn/architecture/data-storage/data-model). Create, read, update, and delete actions using the `operate` API method are operations.
    
-   A **command** consists of one or more operations and affects one or more [records](https://aerospike.com/docs/database/learn/architecture/data-storage/data-model).
    
-   A **transaction** is made up of one or more commands, which occur in a guaranteed order and must all complete for the transaction to be successful.
:::

#### For an interactive Jupyter notebook experience [ ![Binder Hub](https://static.mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/aerospike-examples/interactive-notebooks/main?filepath=python/basic_operations.ipynb)

Basic CRUD (Create, Read, Update, and Delete) operations in Aerospike, and how multiple operations on a record are performed in a single command.

This notebook requires an Aerospike database running on localhost and that Python and the Aerospike Python client are installed (`pip install aerospike`). Visit [Aerospike notebooks repo](https://github.com/aerospike-examples/interactive-notebooks) for additional details and the Docker container.

## Ensure the database is running

This notebook requires that the Aerospike database is running.

```python
!asd >& /dev/null

!pgrep -x asd >/dev/null && echo "Aerospike database is running!" || echo "**Aerospike database is not running!**"
```

Output

```plaintext
Aerospike database is running!
```

## Initialize the client

Initialize the client and connect it to the database.

```python
import aerospike

import sys

config = {

  'hosts': [ ('127.0.0.1', 3000) ]

}

try:

  client = aerospike.client(config).connect()

except:

  import sys

  print("failed to connect to the cluster with", config['hosts'])

  sys.exit(1)

print('Client initialized and connected to database')
```

Output

```plaintext
Client initialized and connected to database
```

## Understanding records in Aerospike

Data in Aerospike consists of records. A record belongs to a namespace (equivalent to a database) and optionally to a set (equivalent to a table). A record has multiple bins (or fields), which are named, strongly-typed containers that hold both atomic (string, integer, bytes) and complex (map, list) data types.

A record has two metadata values:

-   generation: the number of times it has been modified
-   ttl: seconds remaining until record expiration (default = 0; never expire)

Expired records are garbage-collected by the database. On write or touch commands, a record’s ttl is updated based on the specified policy.

### Record structure

The following code cell illustrates the record structure.

::: note
-   key: (namespace, set, user\_key, digest), digest is computed from the first three elements.
-   metadata: `{'gen': generation, 'ttl': ttl}`
-   bins: key-value pairs of data bins dictionary

And also:

-   digest (the bytearray in output) is the actual record unique identifier.
-   user\_key input to produce digest may or may not be stored with the record, and is governed by the key policy.
:::

```python
#  Record structure

#  key: (namespace, set, user_key, digest), digest is computed from first three values

#  metadata: {'gen': generation, 'ttl': ttl}

#  bins: key-value pairs of data bins dictionary

namespace = 'test'

demoset = 'demo'

user_key = 'foo'

meta = {'ttl': 0}

bins = {'name': 'John Doe', 'age': 15, 'gpa': 4.3.0 }

policy = {'key': aerospike.POLICY_KEY_SEND}   # policy to store the user_key along with the record

# insert/update the record

try:

    client.put((namespace, demoset, user_key), bins, meta, policy)

except:

  print('failed to put record')

  sys.exit(1)

print('Successfully wrote the record.')

# read back the record

try:

    (key, metadata, bins)= client.get((namespace, demoset, user_key), policy)

except:

  print('failed to get record')

  sys.exit(1)

print('Successfully read the record.')

print ('Key: ', key)

print ('Metadata: ', metadata)

print ('Bins: ', bins)
```

Output

```plaintext
Successfully wrote the record.

Successfully read the record.

Key:  ('test', 'demo', 'foo', bytearray(b'\xf5~\xc1\x835\xf7\x10\x0c\x04X\xf8\xa6D\xbc\xbcvm\x93G\x1e'))

Metadata:  {'ttl': 2592000, 'gen': 1}

Bins:  {'name': 'John Doe', 'age': 15, 'gpa': 4.3}
```

## Writing records

The Python client’s `put` command writes data to the Aerospike cluster.

### Defining the key

As described above, the key tuple serves as the record’s unique identifier.

Below we define a key tuple in the set `characters` with the user key `bender` in namespace `test`.

```python
# create the key tuple identifying the record

key = ('test', 'characters', 'bender')
```

### Specifying record data

Specify record data in a dict, where the top-level object fields represent the bin names, and field values correspond to bin values.

This example writes six bins: `name`, `serialnum`, `lastsentence`, `composition`, `apartment`, and `quote_cnt`.

```python
# The record data to write to the cluster

bins = {

  'name': 'Bender',

  'serialnum': 2716057,

  'lastsentence': {

    'BBS': "Well, we're boned",

    'TBwaBB': 'I love you, meatbags!',

    'BG': 'Whip harder, Professor!',

    'ltWGY': 'Into the breach, meatbags. Or not, whatever'},

  'composition': [ "40% zinc", "40% titanium", "30% iron", "40% dolomite" ],

  'apartment': bytearray(b'\x24'),

  'quote_cnt': 47

}
```

### Storing the record

Store the record in the database with put.

```python
# Put the record to the database.

try:

    client.put(key, bins)

except:

  print('failed to put record')

  sys.exit(1)

print('Successfully stored the record.')

try:

    (key, metadata, bins) = client.get(key, policy)

except:

  print('failed to get record')

  sys.exit(1)

print ('Bins: ', bins)
```

Output

```plaintext
Successfully stored the record.

Bins:  {'name': 'Bender', 'serialnum': 2716057, 'lastsentence': {'ltWGY': 'Into the breach, meatbags. Or not, whatever', 'BG': 'Whip harder, Professor!', 'BBS': "Well, we're boned", 'TBwaBB': 'I love you, meatbags!'}, 'composition': ['40% zinc', '40% titanium', '30% iron', '40% dolomite'], 'apartment': bytearray(b'$'), 'quote_cnt': 47}
```

### Appending, prepending and incrementing a bin

The following APIs are used to prepend and append string bins, and increment integer bins:

```python
try:

    client.prepend(key, 'name', 'Dr. ')

    client.append(key, 'name', ' Bending Rodriguez')

    client.increment(key, 'quote_cnt', 3)

except:

  print('failed to get record')

  sys.exit(1)

try:

    (key, metadata, bins)= client.get(key, policy)

except:

  print('failed to get record')

  sys.exit(1)

print ('Bins: ', bins)
```

Output

```plaintext
Bins:  {'name': 'Dr. Bender Bending Rodriguez', 'serialnum': 2716057, 'lastsentence': {'ltWGY': 'Into the breach, meatbags. Or not, whatever', 'BG': 'Whip harder, Professor!', 'BBS': "Well, we're boned", 'TBwaBB': 'I love you, meatbags!'}, 'composition': ['40% zinc', '40% titanium', '30% iron', '40% dolomite'], 'apartment': bytearray(b'$'), 'quote_cnt': 50}
```

## Reading records

There are multiple ways to read records from Aerospike database, `get` being the simplest one. You will need the key as the record unique identifier as discussed above. Note the record was written above.

It returns:

-   key — The key tuple of the record that was read.
-   meta — The dict containing the record metadata gen and ttl fields.
-   bins — The dict containing the bins of the record.

Meta and bins are `None` if the record is not found.

```python
# key of the record

key = ('test', 'demo', 'foo')

# Retrieve the record using the key.

try:

    (key, meta, bins) = client.get(key, policy)

except:

  print('failed to get record')

  sys.exit(1)

print('Successfully read the record.')

print ('Key: ', key)

print ('Metadata: ', metadata)

print ('Bins: ', bins)
```

Output

```plaintext
Successfully read the record.

Key:  ('test', 'demo', 'foo', bytearray(b'\xf5~\xc1\x835\xf7\x10\x0c\x04X\xf8\xa6D\xbc\xbcvm\x93G\x1e'))

Metadata:  {'ttl': 2592000, 'gen': 4}

Bins:  {'name': 'John Doe', 'age': 15, 'gpa': 4.3}
```

### Projecting the bins of a record

It is possible to project or read specific bins of a record. The following example illustrates this. Note that the second argument is a tuple of bin names to project.

```python
# retrieve only specified bins in the record

try:

    (key, meta, bins) = client.select(('test','demo','foo'), ('age', 'gpa'))

except:

  print('failed to get record')

  sys.exit(1)

print ('Bins: ', bins)
```

Output

```plaintext
Bins:  {'age': 15, 'gpa': 4.3}
```

### Checking if a record exists

Use `exists` to check the existence of a record in a database. Note, meta is `None` if the record is not found.

```python
# Retrieve the record using a non-existent key.

(key, metadata) = client.exists(('test','demo','foo'), policy)

print('User-key, Metadata: ', key[2], metadata)

(key, metadata) = client.exists(('test','demo','nonexistent'), policy)

print('User-key, Metadata: ', key[2], metadata)
```

Output

```plaintext
User-key, Metadata:  foo {'ttl': 2592000, 'gen': 1}

User-key, Metadata:  nonexistent None
```

#### Batch read commands

The `batch_read` command allows the application to access multiple records.

```python
import pprint

pp = pprint.PrettyPrinter(depth=4)

keys = []

for i in range(1,3):

  key = ('test', 'demo', 'key' + str(i))

  client.put(key, {'batch': i}, policy)

for i in range(1,4):

  key = ('test', 'demo', 'key' + str(i))

  keys.append(key)

brs = client.batch_read(keys)

records = []

for br in brs.batch_records:

    pk = br.key

    if br.result == 0:

        # Successfully retrieved record

        meta = br.record[1]

        bins = br.record[2]

    else:

        # Failed to get record

        # br.record would be None

        meta = None

        bins = None

    records.append((pk, meta, bins))

pp.pprint(records)
```

Output

```plaintext
[(('test',

  'demo',

  'key1',

  bytearray(b'\xec\x91\x19-K\x7f\x8c\xe3]]x\xd3K\xcae\xcb\xaa\xaa\xc9`')),

  {'gen': 1, 'ttl': 2592000},

  {'batch': 1}),

(('test',

  'demo',

  'key2',

  bytearray(b'&o\xc5\xc9\x94\xab\x9d\n\xa1\xc3g\xd9\x9a\xbc\xe6\xd8'

            b'\x9e\x97p\x83')),

  {'gen': 1, 'ttl': 2592000},

  {'batch': 2}),

(('test',

  'demo',

  'key3',

  bytearray(b'cN\x96\xf7\xff\\\xd9hS8\x18\xdc"v\x18\xe2\xe4D\'\xa5')),

  None,

  None)]
```

## Deleting records

To delete records from the database, use the `remove` command.

An exception is thrown if the record does not exist.

```python
# Key of the record to be deleted

key1 = ('test', 'demo', 'key1')

# Delete the record

try:

    client.remove(key1)

except:

  print('failed to delete record: ', key1)

  sys.exit(1)

(key, metadata) = client.exists(key1, policy)

print('Key, metadata: ', key1, metadata)

print('Successfully deleted ', key1)

# will throw an exception

nokey = ('test', 'demo', 'non-existent')

try:

    client.remove(key)

except:

  print('failed to delete record: ', nokey)
```

Output

```plaintext
Key, metadata:  ('test', 'demo', 'key1') None

Successfully deleted  ('test', 'demo', 'key1')

failed to delete record:  ('test', 'demo', 'non-existent')
```

## Multiple operations on a single record

Multiple operations on a single a record can be conveniently performed in a single-record command. Multiple updates as well as reads of a record may be performed atomically in a single `operate` command. Commands are performed in the order they are specified. Following is a full example of a multi-operation command.

```python
from __future__ import print_function

import aerospike

from aerospike_helpers.operations import operations as op_helpers

from aerospike import exception as ex

import sys

config = { 'hosts': [('127.0.0.1', 3000)] }

client = aerospike.client(config).connect()

try:

    key = ('test', 'demo', 1)

    client.put(key, {'age': 25, 'career': 'delivery boy'})

    ops = [

        op_helpers.increment("age", 1000),

        op_helpers.write("name", "J."),

        op_helpers.prepend("name", "Phillip "),

        op_helpers.append("name", " Fry"),

        op_helpers.read("name"),

        op_helpers.read("career"),

        op_helpers.read("age")

    ]

    (key, metadata, bins) = client.operate(key, ops, {'ttl':0}, {'total_timeout':500})

except ex.AerospikeError as e:

    print("Error: {0} [{1}]".format(e.msg, e.code))

    sys.exit(1)

print('Key: ', key)

print('--------------------------')

print('Metadata: ', metadata)

print('--------------------------')

print('Bins: ', bins) # shows only bins specified in read commands
```

Output

```plaintext
Key:  ('test', 'demo', 1, bytearray(b'\xb7\xf4\xb88\x89\xe2\xdag\xdeh>\x1d\xf6\x91\x9a\x1e\xac\xc4F\xc8'))

--------------------------

Metadata:  {'ttl': 2592000, 'gen': 2}

--------------------------

Bins:  {'name': 'Phillip J. Fry', 'career': 'delivery boy', 'age': 1025}
```

### Multi-op example: read and delete in one request

The example shows reading and deleting a record in a single command. The record was created above.

```python
from aerospike_helpers.operations import operations

key = ('test', 'demo', 1)

ops = [ operations.read('name'),

        operations.delete() ]

_, _, bins = client.operate(key, ops)

print('Bins: ', bins)

# will throw an exception

(key_, metadata) = client.exists(key, policy)

print('Key, metadata: ', key, metadata)

print('Successfully deleted ', key)
```

Output

```plaintext
Bins:  {'name': 'Phillip J. Fry'}

Key, metadata:  ('test', 'demo', 1) None

Successfully deleted  ('test', 'demo', 1)
```

## Next steps

Visit [Aerospike notebooks repo](https://github.com/aerospike-examples/interactive-notebooks) to run additional Aerospike notebooks. To run a different notebook, download the notebook from the repo to your local machine, and then click on **File > Open**, and select Upload.