Create
For the complete documentation index see: llms.txt
All documentation pages available in markdown.
Jump to the Code block for a combined complete example.
Setup
The following examples will use the setup and record structure below to illustrate single record creation in an Aerospike database.
import ( "log"
"github.com/aerospike/aerospike-client-go/v8" ast "github.com/aerospike/aerospike-client-go/v8/types")
// Establishes a connection to the serverclient, err := aerospike.NewClient("127.0.0.1", 3000)if err != nil { log.Fatal(err)}defer client.Close()The record structure:
Occurred: IntegerReported: IntegerPosted: IntegerReport: Map{ shape: List, summary: String, city: String, state: String, duration: String}Location: GeoJSONKey
The key is a tuple made up of: (namespace, set, user-defined key).
The following example creates a key using the sandbox namespace, ufodata set, and user-defined key 5001. The examples that follow reuse this key.
// Create the record keykey, err := aerospike.NewKey("sandbox", "ufodata", 5001)if err != nil { log.Fatal(err)}Policies
Write policies define additional semantics for the write operation. You can set write policies on a per-command basis.
The following example creates a new write policy container object that sets the send key policy to true. This stores the user-defined key with the record, and returns it with read commands.
// Create new write policypolicy := aerospike.NewWritePolicy(0, 0)policy.SendKey = trueThe following example creates a new write policy container object that sets the send key policy to true. This stores the user-defined key with the record, which increases per-record storage, and returns it with read commands. Leave it unset if your application reconstructs keys itself and does not need to read the original key back.
PutBins creates a record if it does not exist and merges the supplied bins if it does. The default RecordExistsAction is UPDATE. Bins that a later write does not name stay in the record.
| Action | Description |
|---|---|
UPDATE | Create the record if it is missing. Merge bins if it exists. This is the default. |
UPDATE_ONLY | Merge bins only if the record already exists. |
REPLACE | Create the record if it is missing. Replace all bins if it exists. |
REPLACE_ONLY | Replace all bins only if the record already exists. |
CREATE_ONLY | Create the record only if it does not already exist. |
To reject the write when the record already exists, copy a write policy and set CREATE_ONLY. The server then returns KEY_EXISTS_ERROR instead of merging. Copy the policy rather than mutating a shared default so concurrent commands are unaffected.
createPolicy := aerospike.NewWritePolicy(0, 0)createPolicy.SendKey = truecreatePolicy.RecordExistsAction = aerospike.CREATE_ONLY
err = client.PutBins(createPolicy, key, aerospike.NewBin("status", "new"))if err != nil { if err.Matches(ast.KEY_EXISTS_ERROR) { log.Print("The record was already created.") } else { log.Fatal(err) }}Matches tests the server result code, which is what you need to distinguish outcomes such as KEY_EXISTS_ERROR from GENERATION_ERROR. The returned Error also works with errors.Is against the client’s sentinel errors, such as aerospike.ErrKeyNotFound. Use Matches for result codes and errors.Is for sentinels; see Best practices.
Record expiration
The second argument to NewWritePolicy is the record time-to-live (TTL) in seconds. Leaving it at 0 does not mean “never expire.” It means “use the namespace default-ttl.” If that namespace has a finite default-ttl, records written with the default policy expire.
| Expiration | Meaning |
|---|---|
aerospike.TTLServerDefault (0) | Use the namespace default-ttl. |
aerospike.TTLDontExpire | Never expire. |
aerospike.TTLDontUpdate | Leave the existing record’s TTL unchanged. |
| positive | TTL in seconds from now. |
// Expire 60 seconds from now.expiringPolicy := aerospike.NewWritePolicy(0, 60)Concurrent writers
Each write increments the record generation. Without a generation check, the last write wins: a write overwrites the bins it names using whatever the record held at the time, and the writer whose value was replaced receives no error.
To refuse an update when another writer has already changed the record, set GenerationPolicy to EXPECT_GEN_EQUAL and pass the generation you last read. The server then returns GENERATION_ERROR instead of overwriting the other writer’s bins.
record, err := client.Get(nil, key)if err != nil { log.Fatal(err)}
writePolicy := aerospike.NewWritePolicy(record.Generation, aerospike.TTLDontUpdate)writePolicy.GenerationPolicy = aerospike.EXPECT_GEN_EQUAL
err = client.PutBins(writePolicy, key, aerospike.NewBin("status", "updated"))if err != nil { if err.Matches(ast.GENERATION_ERROR) { log.Print("Another writer updated the record first.") } else { log.Fatal(err) }}Write timeouts
A timed-out write may already have succeeded on the server. Check err.IsInDoubt() before retrying a non-idempotent create. Writes default to MaxRetries = 0, so the client does not retry them automatically.
err = client.PutBins(createPolicy, key, aerospike.NewBin("status", "new"))if err != nil { if err.IsInDoubt() { log.Print("Write timed out and may have succeeded.") } else { log.Fatal(err) }}Retrying an in-doubt CREATE_ONLY write cannot produce a duplicate, because the server still enforces create-only semantics on the retry. What the retry cannot tell you is who created the record: a KEY_EXISTS_ERROR means either that your own in-doubt write committed, or that a different writer created the record in the meantime. Reading the record before retrying does not resolve this and introduces a race, because another writer can create it between the read and the retry.
Where that distinction matters, write a value that identifies the writer, such as a request ID bin, and read it back after a KEY_EXISTS_ERROR to determine whether the record is yours.
See Update for UPDATE_ONLY, REPLACE, and REPLACE_ONLY.
Create a record
A record is the basic unit of storage in the database. A record is composed of: (key, metadata, bins).
Setup
Expand the block below to see the creation of the variables used in the write example below.
View the data creation
// Create a list of shapes to add to the report mapshape := []string{"circle", "flash", "disc"}
// Create the report mapreportMap := map[string]interface{}{ "city": "Ann Arbor", "state": "Michigan", "shape": shape, "duration": "5 minutes", "summary": "Large flying disc flashed in the sky above the student union. Craziest thing I've ever seen!"}
// Format coordinates as a GeoJSON stringgeoLoc := "{\"type\":\"Point\", \"coordinates\":[42.2808,83.7430]}"Write
The following example shows the creation of the bins and the writing of the record to the database.
// Create the bins as Bin("binName", value)occurred := aerospike.NewBin("occurred", 20220531)reported := aerospike.NewBin("reported", 20220601)posted := aerospike.NewBin("posted", 20220601)// reportMap defined in the section abovereport := aerospike.NewBin("report", reportMap)// geoLoc defined in the section abovelocation := aerospike.NewBin("location", aerospike.NewGeoJSONValue(geoLoc))
// Write the record to Aerospikeerr = client.PutBins(policy, key, occurred, reported, posted, report, location)if err != nil { log.Fatal(err)}Code block
Expand this section for a single code block to create a record
import ( "log"
"github.com/aerospike/aerospike-client-go/v8")
func main() { // Establishes a connection to the server client, err := aerospike.NewClient("127.0.0.1", 3000) if err != nil { log.Fatal(err) } defer client.Close()
// Create new write policy. // TTL 0 inherits the namespace default-ttl; use aerospike.TTLDontExpire to never expire. policy := aerospike.NewWritePolicy(0, 0) policy.SendKey = true
// Create the record key key, err := aerospike.NewKey("sandbox", "ufodata", 5001) if err != nil { log.Fatal(err) }
// Create a list of shapes to add to the report map shape := []string{"circle", "flash", "disc"}
// Create the report map reportMap := map[string]interface{}{ "city": "Ann Arbor", "state": "Michigan", "shape": shape, "duration": "5 minutes", "summary": "Large flying disc flashed in the sky above the student union. Craziest thing I've ever seen!"}
// Format coordinates as a GeoJSON string geoLoc := "{\"type\":\"Point\", \"coordinates\":[42.2808,83.7430]}"
// Create the bins as Bin("binName", value) occurred := aerospike.NewBin("occurred", 20220531) reported := aerospike.NewBin("reported", 20220601) posted := aerospike.NewBin("posted", 20220601) // reportMap defined in the section above report := aerospike.NewBin("report", reportMap) // geoLoc defined in the section above location := aerospike.NewBin("location", aerospike.NewGeoJSONValue(geoLoc))
// Write the record to Aerospike err = client.PutBins(policy, key, occurred, reported, posted, report, location) if err != nil { log.Fatal(err) }}