This is information on how to use the library. For docs on working on the library itself see readme-dev.md.
This library requires go 1.11 or later.
API reference: https://godoc.org/github.com/ravendb/ravendb-go-client
This library is in beta state. All the basic functionality works and passes extensive test suite, but the API for more esoteric features might change.
If you encounter bugs, have suggestions or feature requests, please open an issue.
Documentation
To learn basics of RavenDB, read RavenDB Documentation or Dive into RavenDB.
Getting started
Full source code of those examples is in examples
directory.
To run a a specific example, e.g. crudStore
, you can run:
.\scripts\run_example.ps1 crudStore
: works on mac / linux if you have powershell installedgo run examples\log.go examples\main.go crudStore
: on mac / linux change paths to examples/log.go
etc.
- Import the package
import (
ravendb "github.com/ravendb/ravendb-go-client"
)
- Initialize document store (you should have one DocumentStore instance per application)
func getDocumentStore(databaseName string) (*ravendb.DocumentStore, error) {
serverNodes := []string{"http://live-test.ravendb.net"}
store := ravendb.NewDocumentStore(serverNodes, databaseName)
if err := store.Initialize(); err != nil {
return nil, err
}
return store, nil
}
To setup an document store with security, you'll need to provide the client certificate for authentication.
Here is how to setup a document store with a certificate:
func getDocumentStore(databaseName string) (*ravendb.DocumentStore, error) {
cerPath := "/path/to/certificate.crt"
keyPath := "/path/to/certificate.key"
serverNodes := []string{"https://a.tasty.ravendb.run",
"https://b.tasty.ravendb.run", "https://c.tasty.ravendb.run"}
cer, err := tls.LoadX509KeyPair(cerPath, keyPath)
if err != nil {
return nil, err
}
store := ravendb.NewDocumentStore(serverNodes, databaseName)
store.Certificate = &cer
x509cert, err := x509.ParseCertificate(cer.Certificate[0])
if err != nil {
return nil, err
}
store.TrustStore = x509cert
if err := store.Initialize(); err != nil {
return nil, err
}
return store, nil
}
If you are using an encrypted certificate, see the sample code on how to translate that to tls.Certificate
here: https://play.golang.org/p/8OYTuZtZIQ
- Open a session and close it when done
session, err = store.OpenSession()
if err != nil {
log.Fatalf("store.OpenSession() failed with %s", err)
}
session.Close()
- Call
SaveChanges()
to persist changes in a session:
var e *northwind.Employee
err = session.Load(&e, "employees/7-A")
if err != nil {
log.Fatalf("session.Load() failed with %s\n", err)
}
origName := e.FirstName
e.FirstName = e.FirstName + "Changed"
err = session.Store(e)
if err != nil {
log.Fatalf("session.Store() failed with %s\n", err)
}
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with %s\n", err)
}
var e2 *northwind.Employee
err = session.Load(&e2, "employees/7-A")
if err != nil {
log.Fatalf("session.Load() failed with %s\n", err)
}
fmt.Printf("Updated Employee.FirstName from '%s' to '%s'\n", origName, e2.FirstName)
See loadUpdateSave()
in examples/main.go for full example.
CRUD example
Storing documents
product := &northwind.Product{
Name: "iPhone X",
PricePerUnit: 999.99,
Category: "electronis",
ReorderLevel: 15,
}
err = session.Store(product)
if err != nil {
log.Fatalf("session.Store() failed with %s\n", err)
}
See crudStore()
in examples/main.go for full example.
Loading documents
var e *northwind.Employee
err = session.Load(&e, "employees/7-A")
if err != nil {
log.Fatalf("session.Load() failed with %s\n", err)
}
fmt.Printf("employee: %#v\n", e)
See crudLoad()
in examples/main.go for full example.
Loading documents with includes
Some entities point to other entities via id. For example Employee
has ReportsTo
field which is an id of Employee
that it reports to.
To improve performance by minimizing number of server requests, we can use includes functionality to load such linked entities.
var e *northwind.Employee
err = session.Include("ReportsTo").Load(&e, "employees/5-A")
if err != nil {
log.Fatalf("session.Load() failed with %s\n", err)
}
if e.ReportsTo == "" {
fmt.Printf("Employee with id employees/5-A doesn't report to anyone\n")
return
}
numRequests := session.GetNumberOfRequests()
var reportsTo *northwind.Employee
err = session.Load(&reportsTo, e.ReportsTo)
if err != nil {
log.Fatalf("session.Load() failed with %s\n", err)
}
if numRequests != session.GetNumberOfRequests() {
fmt.Printf("Something's wrong, this shouldn't send a request to the server\n")
} else {
fmt.Printf("Loading e.ReportsTo employee didn't require a new request to the server because we've loaded it in original requests thanks to using Include functionality\n")
}
See crudLoadWithInclude()
in examples/main.go for full example.
Updating documents
var p *northwind.Product
err = session.Load(&p, productID)
if err != nil {
log.Fatalf("session.Load() failed with %s\n", err)
}
origPrice = p.PricePerUnit
newPrice = origPrice + 10
p.PricePerUnit = newPrice
err = session.Store(p)
if err != nil {
log.Fatalf("session.Store() failed with %s\n", err)
}
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with %s\n", err)
}
See crudUpdate()
in examples/main.go for full example.
Deleting documents
Delete using entity:
var p *northwind.Product
err = session.Load(&p, productID)
if err != nil {
log.Fatalf("session.Load() failed with %s\n", err)
}
err = session.Delete(p)
if err != nil {
log.Fatalf("session.Delete() failed with %s\n", err)
}
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with %s\n", err)
}
See crudDeleteUsingEntity()
in examples/main.go for full example.
Entity must be a value that we either stored in the database in the current session via Store()
or loaded from database using Load()
, LoadMulti()
, query etc.
Delete using id:
err = session.DeleteByID(productID, "")
if err != nil {
log.Fatalf("session.Delete() failed with %s\n", err)
}
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with %s\n", err)
}
Second argument to DeleteByID
is optional changeVector
, for fine-grain concurrency control.
See crudDeleteUsingID()
in examples/main.go for full example.
Querying documents
Selecting what to query
First you need to decide what to query.
RavenDB stores documents in collections. By default each type (struct) is stored in its own collection e.g. all Employee
structs are stored in employees
collection.
You can query by collection name:
q := session.QueryCollection("employees")
See queryCollectionByName()
in examples/main.go for full example.
To get a collection name for a given type use ravendb.GetCollectionNameDefault(&MyStruct{})
.
You can query a collection for a given type:
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
See queryCollectionByType()
in examples/main.go for full example.
You can query an index:
q := session.QueryIndex("Orders/ByCompany")
See queryIndex()
in examples/main.go for full example.
Limit what is returned
tp := reflect.TypeOf(&northwind.Product{})
q := session.QueryCollectionForType(tp)
q = q.WaitForNonStaleResults(0)
q = q.WhereEquals("Name", "iPhone X")
q = q.OrderBy("PricePerUnit")
q = q.Take(2)
See queryComplex()
in examples/main.go for full example.
Obtain the results
You can get all matching results:
var products []*northwind.Product
err = q.GetResults(&products)
See queryComplex()
in examples/main.go for full example.
You can get just first one:
var first *northwind.Employee
err = q.First(&first)
See queryFirst()
in examples/main.go for full example.
SelectFields() - projections using a single field
q = q.SelectFields(reflect.TypeOf(""), "FirstName")
var names []string
err = q.GetResults(&names)
See querySelectSingleField()
in examples/main.go for full example.
SelectFields() - projections using multiple fields
type employeeNameTitle struct {
FirstName string
Title string
}
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.SelectFields(reflect.TypeOf(&employeeNameTitle{}), "FirstName", "Title")
See querySelectFields()
in examples/main.go for full example.
Distinct()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.SelectFields(reflect.TypeOf(""), "Title")
q = q.Distinct()
See queryDistinct()
in examples/main.go for full example.
WhereEquals() / WhereNotEquals()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.WhereEquals("Title", "Sales Representative")
See queryEquals()
in examples/main.go for full example.
WhereIn
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.WhereIn("Title", []interface{}{"Sales Representative", "Sales Manager"})
See queryIn()
in examples/main.go for full example.
WhereStartsWith() / WhereEndsWith()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.WhereStartsWith("FirstName", "Ro")
See queryStartsWith()
and queryEndsWith
in examples/main.go for full example.
WhereBetween()
tp := reflect.TypeOf(&northwind.Order{})
q := session.QueryCollectionForType(tp)
q = q.WhereBetween("Freight", 11, 13)
See queryBetween()
in examples/main.go for full example.
WhereGreaterThan() / WhereGreaterThanOrEqual() / WhereLessThan() / WhereLessThanOrEqual()
tp := reflect.TypeOf(&northwind.Order{})
q := session.QueryCollectionForType(tp)
q = q.WhereGreaterThan("Freight", 11)
See queryGreater()
in examples/main.go for full example.
WhereExists()
Checks if the field exists.
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.WhereExists("ReportsTo")
See queryExists()
in examples/main.go for full example.
ContainsAny() / ContainsAll()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.ContainsAny("FirstName", []interface{}{"Anne", "Nancy"})
See queryContainsAny()
in examples/main.go for full example.
Search()
Performs full-text search:
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.Search("FirstName", "Anne Nancy")
See querySearch()
in examples/main.go for full example.
OpenSubclause() / CloseSubclause()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.WhereEquals("FirstName", "Steven")
q = q.OrElse()
q = q.OpenSubclause()
q = q.WhereEquals("Title", "Sales Representative")
q = q.WhereEquals("LastName", "Davolio")
q = q.CloseSubclause()
See querySubclause()
in examples/main.go for full example.
Not()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.Not()
q = q.WhereEquals("FirstName", "Steven")
See queryNot()
in examples/main.go for full example.
AndAlso() / OrElse()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.WhereEquals("FirstName", "Steven")
q = q.OrElse()
q = q.WhereEquals("FirstName", "Nancy")
See queryOrElse()
in examples/main.go for full example.
UsingDefaultOperator()
Sets default operator (which will be used if no AndAlso()
/ OrElse()
was called. Just after query instantiation, OR is used as default operator. Default operator can be changed only adding any conditions.
OrderBy() / RandomOrdering()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.OrderBy("FirstName")
See queryOrderBy()
in examples/main.go for full example.
Take()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.OrderByDescending("FirstName")
q = q.Take(2)
See queryTake()
in examples/main.go for full example.
Skip()
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.OrderByDescending("FirstName")
q = q.Take(2)
q = q.Skip(1)
See querySkip()
in examples/main.go for full example.
Getting query statistics
To obtain query statistics use Statistics()
method.
var stats *ravendb.QueryStatistics
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
q = q.WhereGreaterThan("FirstName", "Bernard")
q = q.OrderByDescending("FirstName")
q.Statistics(&stats)
Statistics:
Statistics:
{IsStale: false,
DurationInMs: 0,
TotalResults: 7,
SkippedResults: 0,
Timestamp: 2019-02-13 02:57:31.5226409 +0000 UTC,
IndexName: "Auto/employees/ByLastNameAndReportsToAndSearch(FirstName)AndTitle",
IndexTimestamp: 2019-02-13 02:57:31.5226409 +0000 UTC,
LastQueryTime: 2019-02-13 03:50:25.7602429 +0000 UTC,
TimingsInMs: {},
ResultEtag: 7591488513381790088,
ResultSize: 0,
ScoreExplanations: {}}
See queryStatistics()
in examples/main.go for full example.
GetResults() / First() / Single() / Count()
GetResults()
- returns all results
First()
- first result
Single()
- first result, returns error if there's more entries
Count()
- returns the number of the results (not affected by take())
See queryFirst()
, querySingle()
and queryCount()
in examples/main.go for full example.
Attachments
Store attachments
fileStream, err := os.Open(path)
if err != nil {
log.Fatalf("os.Open() failed with '%s'\n", err)
}
defer fileStream.Close()
fmt.Printf("new employee id: %s\n", e.ID)
err = session.Advanced().Attachments().Store(e, "photo.png", fileStream, "image/png")
if err != nil {
log.Fatalf("session.Advanced().Attachments().Store() failed with '%s'\n", err)
}
err = session.SaveChanges()
See storeAttachments()
in examples/main.go for full example.
Get attachments
attachment, err := session.Advanced().Attachments().Get(docID, "photo.png")
if err != nil {
log.Fatalf("session.Advanced().Attachments().Get() failed with '%s'\n", err)
}
defer attachment.Close()
fmt.Print("Attachment details:\n")
pretty.Print(attachment.Details)
var attachmentData bytes.Buffer
n, err := io.Copy(&attachmentData, attachment.Data)
if err != nil {
log.Fatalf("io.Copy() failed with '%s'\n", err)
}
fmt.Printf("Attachment size: %d bytes\n", n)
Attachment details:
{AttachmentName: {Name: "photo.png",
Hash: "MvUEcrFHSVDts5ZQv2bQ3r9RwtynqnyJzIbNYzu1ZXk=",
ContentType: "image/png",
Size: 4579},
ChangeVector: "A:4905-dMAeI9ANZ06DOxCRLnSmNw",
DocumentID: "employees/44-A"}
Attachment size: 4579 bytes
See getAttachments()
in examples/main.go for full example.
Check if attachment exists
name := "photo.png"
exists, err := session.Advanced().Attachments().Exists(docID, name)
if err != nil {
log.Fatalf("session.Advanced().Attachments().Exists() failed with '%s'\n", err)
}
See checkAttachmentExists()
in examples/main.go for full example.
Get attachment names
names, err := session.Advanced().Attachments().GetNames(doc)
if err != nil {
log.Fatalf("session.Advanced().Attachments().GetNames() failed with '%s'\n", err)
}
Attachment names:
[{Name: "photo.png",
Hash: "MvUEcrFHSVDts5ZQv2bQ3r9RwtynqnyJzIbNYzu1ZXk=",
ContentType: "image/png",
Size: 4579}]
See getAttachmentNames()
in examples/main.go for full example.
Bulk insert
When storing multiple documents, use bulk insertion.
bulkInsert := store.BulkInsert("")
names := []string{"Anna", "Maria", "Miguel", "Emanuel", "Dayanara", "Aleida"}
for _, name := range names {
e := &northwind.Employee{
FirstName: name,
}
id, err := bulkInsert.Store(e, nil)
if err != nil {
log.Fatalf("bulkInsert.Store() failed with '%s'\n", err)
}
}
err = bulkInsert.Close()
See bulkInsert()
in examples/main.go for full example.
Observing changes in the database
Listen for database changes e.g. document changes.
changes := store.Changes("")
err = changes.EnsureConnectedNow()
if err != nil {
log.Fatalf("changes.EnsureConnectedNow() failed with '%s'\n", err)
}
cb := func(change *ravendb.DocumentChange) {
fmt.Print("change:\n")
pretty.Print(change)
}
docChangesCancel, err := changes.ForAllDocuments(cb)
if err != nil {
log.Fatalf("changes.ForAllDocuments() failed with '%s'\n", err)
}
defer docChangesCancel()
e := &northwind.Employee{
FirstName: "Jon",
LastName: "Snow",
}
err = session.Store(e)
if err != nil {
log.Fatalf("session.Store() failed with '%s'\n", err)
}
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with '%s'\n", err)
}
Example change:
{Type: "Put",
ID: "Raven/Hilo/employees",
CollectionName: "@hilo",
ChangeVector: "A:4892-bJERJNLunE+4xQ/yDEuk1Q"}
See changes()
in examples/main.go for full example.
Streaming
Streaming allows interating over documents matching certain criteria.
It's useful when there's a large number of results as it limits memory
use by reading documents in batches (as opposed to all at once).
Stream documents with ID prefix
Here we iterate over all documents in products
collection:
args := &ravendb.StartsWithArgs{
StartsWith: "products/",
}
iterator, err := session.Advanced().Stream(args)
if err != nil {
log.Fatalf("session.Advanced().Stream() failed with '%s'\n", err)
}
for {
var p *northwind.Product
streamResult, err := iterator.Next(&p)
if err != nil {
if err == io.EOF {
err = nil
} else {
log.Fatalf("iterator.Next() failed with '%s'\n", err)
}
break
}
}
See streamWithIDPrefix()
in examples/main.go for full example.
This returns:
streamResult:
{ID: "products/1-A",
ChangeVector: "A:96-bJERJNLunE+4xQ/yDEuk1Q",
Metadata: {},
Document: ... same as product but as map[string]interface{} ...
product:
{ID: "products/1-A",
Name: "Chai",
Supplier: "suppliers/1-A",
Category: "categories/1-A",
QuantityPerUnit: "10 boxes x 20 bags",
PricePerUnit: 18,
UnitsInStock: 1,
UnistsOnOrder: 0,
Discontinued: false,
ReorderLevel: 10}
Stream query results
tp := reflect.TypeOf(&northwind.Product{})
q := session.QueryCollectionForType(tp)
q = q.WhereGreaterThan("PricePerUnit", 15)
q = q.OrderByDescending("PricePerUnit")
iterator, err := session.Advanced().StreamQuery(q, nil)
if err != nil {
log.Fatalf("session.Advanced().StreamQuery() failed with '%s'\n", err)
}
See streamQueryResults()
in examples/main.go for full example.
Revisions
Note: make sure to enable revisions in a given store using NewConfigureRevisionsOperation
operation.
e := &northwind.Employee{
FirstName: "Jon",
LastName: "Snow",
}
err = session.Store(e)
if err != nil {
log.Fatalf("session.Store() failed with '%s'\n", err)
}
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with '%s'\n", err)
}
e.FirstName = "Jhonny"
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with '%s'\n", err)
}
var revisions []*northwind.Employee
err = session.Advanced().Revisions().GetFor(&revisions, e.ID)
See revisions()
in examples/main.go for full example.
Returns:
[{ID: "employees/43-A",
LastName: "Snow",
FirstName: "Jhonny",
Title: "",
Address: nil,
HiredAt: {},
Birthday: {},
HomePhone: "",
Extension: "",
ReportsTo: "",
Notes: [],
Territories: []},
{ID: "employees/43-A",
LastName: "Snow",
FirstName: "Jon",
Title: "",
Address: nil,
HiredAt: {},
Birthday: {},
HomePhone: "",
Extension: "",
ReportsTo: "",
Notes: [],
Territories: []}]
Suggestions
Suggestions provides similarity queries. Here we're asking for FirstName
values similar to Micael
and the database suggests Michael
.
index := ravendb.NewIndexCreationTask("EmployeeIndex")
index.Map = "from doc in docs.Employees select new { doc.FirstName }"
index.Suggestion("FirstName")
err = store.ExecuteIndex(index, "")
if err != nil {
log.Fatalf("store.ExecuteIndex() failed with '%s'\n", err)
}
tp := reflect.TypeOf(&northwind.Employee{})
q := session.QueryCollectionForType(tp)
su := ravendb.NewSuggestionWithTerm("FirstName")
su.Term = "Micael"
suggestionQuery := q.SuggestUsing(su)
results, err := suggestionQuery.Execute()
See suggestions()
in examples/main.go for full example.
Returns:
{FirstName: {Name: "FirstName",
Suggestions: ["michael"]}}
Advanced patching
To update documents more efficiently than sending the whole document, you can patch just a given field or atomically add/substract values
of numeric fields.
err = session.Advanced().IncrementByID(product.ID, "PricePerUnit", 15)
if err != nil {
log.Fatalf("session.Advanced().IncrementByID() failed with %s\n", err)
}
err = session.Advanced().Patch(product, "Category", "expensive products")
if err != nil {
log.Fatalf("session.Advanced().PatchEntity() failed with %s\n", err)
}
err = session.SaveChanges()
if err != nil {
log.Fatalf("session.SaveChanges() failed with %s\n", err)
}
See advancedPatching()
in examples/main.go for full example.
Subscriptions
opts := ravendb.SubscriptionCreationOptions{
Query: "from Products where PricePerUnit > 17 and PricePerUnit < 19",
}
subscriptionName, err := store.Subscriptions().Create(&opts, "")
if err != nil {
log.Fatalf("store.Subscriptions().Create() failed with %s\n", err)
}
wopts := ravendb.NewSubscriptionWorkerOptions(subscriptionName)
worker, err := store.Subscriptions().GetSubscriptionWorker(tp, wopts, "")
if err != nil {
log.Fatalf("store.Subscriptions().GetSubscriptionWorker() failed with %s\n", err)
}
results := make(chan *ravendb.SubscriptionBatch, 16)
cb := func(batch *ravendb.SubscriptionBatch) error {
results <- batch
return nil
}
err = worker.Run(cb)
if err != nil {
log.Fatalf("worker.Run() failed with %s\n", err)
}
select {
case batch := <-results:
fmt.Print("Batch of subscription results:\n")
pretty.Print(batch)
case <-time.After(time.Second * 5):
fmt.Printf("Timed out waiting for first subscription batch\n")
}
_ = worker.Close()
See subscriptions()
in examples/main.go for full example.
Cluster wide transactions
Setup a session
To set session transaction as cluster wide you've to set TransactionMode
in SessionOptions
as TransactionMode_ClusterWide
session, err := store.OpenSessionWithOptions(&ravendb.SessionOptions{
Database: "",
RequestExecutor: nil,
TransactionMode: ravendb.TransactionMode_ClusterWide,
DisableAtomicDocumentWritesInClusterWideTransaction: nil,
})
Cluster transactions
In order to create cluster transactions you have to get
cluster transaction object from your session or you can use it as fluent API.
clusterTransaction := session.Advanced().ClusterTransaction()
In case of wrong session configuration clusterTransaction
object will be nil.
Inserting new CompareExchangeValue
objectToInsert := &YourStruct{[...]}
key := "exampleKeyOfItem"
value, error := session.Advanced().ClusterTransaction().CreateCompareExchangeValue(key, objectToInsert)
Getting existing CompareExchangeValue from server
You can retrieve your value using various methods.
- Get value by key
dataType := reflect.TypeOf(&YourStruct{})
key := "exampleKeyOfItem"
value, error := session.Advanced().ClusterTransaction().GetCompareExchangeValue(dataType, key)
- Get values by keys
dataType := reflect.TypeOf(&YourStruct{})
keys := []string{"item/1", "item/2"}
value, error := session.Advanced().ClusterTransaction().GetCompareExchangeValuesWithKeys(dataType, keys)
Returns map where keys are identifiers.
Get values whose IDs start with a string
dataType := reflect.TypeOf(&YourStruct{})
startsWith := "item/"
start := 0
pageSize := 25
values, error := session.Advanced().ClusterTransaction().GetCompareExchangeValues(dataType, startsWith, start, pageSize)
Returns map where keys are identifiers.
Delete CompareExchangeValue
By field key and index
key := "item/1"
index := 5
err := session.Advanced().ClusterTransaction().DeleteCompareExchangeValueByKey(key, index)
By CompareExchangeValue object
var compareExchangeValue *ravendb.CompareExchangeValue
compareExchangeValue , error := session.Advanced().ClusterTransaction().GetCompareExchangeValue[...]
err := session.Advanced().ClusterTransaction().DeleteCompareExchangeValue(compareExchangeValue)