BuntDB Documentation

repository·master·Indexed 26 days ago

https://github.com/tidwall/buntdb

BuntDB is a low-level, in-memory, ACID-compliant key/value store written in pure Go. It supports persistence to disk via an Append-Only File (AOF) and provides advanced indexing capabilities, including custom B-Tree indexes, spatial (R-tree) indexing for k-Nearest Neighbors search, and JSON document indexing using GJSON. The library features a transactional model with concurrent read-only views and single-writer updates, as well as support for Time-To-Live (TTL) data expiration.

Tokens
4.6K
Snippets
13
Records
39
Agent score
39%

What's inside BuntDB

  1. Create Collate i18n Indexes

    master

    Using the github.com/tidwall/collate package, you can create indexes that follow specific language collation rules (e.g., case-insensitive or numeric sorting).

    First, install the dependency:

    go get -u github.com/tidwall/collate

    Then use collate.IndexString or collate.IndexJSON to define the collation rule.

  2. Workaround: Delete keys while iterating

    master

    BuntDB does not support deleting a key while currently iterating over it. To delete keys based on a condition during iteration, collect the keys into a slice first, then perform the deletions in a separate loop after the iterator has completed.

    var delkeys []string
    tx.AscendKeys("object:*", func(k, v string) bool {
    	if someCondition(k) == true {
    		delkeys = append(delkeys, k)
    	}
    	return true // continue
    })
    for _, k := range delkeys {
    	if _, err = tx.Delete(k); err != nil {
    		return err
    	}
    }
  3. Use Transactions in BuntDB

    master

    All reads and writes in BuntDB must occur within a transaction. BuntDB supports multiple concurrent read-only transactions but only one write transaction at a time.

    Important: Always use the Tx object provided by the transaction function for all operations. Do not access the original DB object inside a transaction to avoid deadlocks or side effects.

  4. Configure BuntDB SyncPolicy and AutoShrink

    master

    BuntDB uses an Append-Only File (AOF) for durability. You can configure how data is synced to disk and how the AOF is automatically managed via the buntdb.Config struct.

    To update configuration, use ReadConfig followed by SetConfig.

  5. Create JSON Indexes

    master

    BuntDB allows you to create indexes on specific fields within JSON documents using buntdb.IndexJSON. This enables efficient searching and sorting based on JSON paths. The implementation uses GJSON for path resolution.

    db.CreateIndex("last_name", "*", buntdb.IndexJSON("name.last"))
    db.CreateIndex("age", "*", buntdb.IndexJSON("age"))
  6. Open a BuntDB database

    master

    Use buntdb.Open() to create or open a database. You can provide a file path for persistence or use :memory: for an in-memory database that does not persist to disk.

    package main
    
    import (
    	"log"
    
    	"github.com/tidwall/buntdb"
    )
    
    func main() {
    	// Open the data.db file. It will be created if it doesn't exist.
    	db, err := buntdb.Open("data.db")
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer db.Close()
    
    	// To open an in-memory database:
    	// db, err := buntdb.Open(":memory:")
    }
  7. Create Descending Ordered Indexes

    master

    To create an index with descending order, wrap the specific index function with buntdb.Desc. This is particularly useful in multi-value indexes where you want different columns to have different sort directions.

    db.CreateIndex("last_name_age", "*",
        buntdb.IndexJSON("name.last"),
        buntdb.Desc(buntdb.IndexJSON("age")),
    )
  8. Create Custom Indexes

    master
    You can create indexes to order and iterate over values rather than just keys. Use db.CreateIndex(name, pattern, indexFunc). The pattern uses wildcards (like *) to filter which keys are included in the index.
  9. Create Multi-Value Indexes

    master

    You can create a multi-value index (similar to a multi-column index in SQL) by passing multiple index functions to CreateIndex. This allows you to join multiple values on a single index for complex sorting and searching.

    db.CreateIndex("last_name_age", "*", buntdb.IndexJSON("name.last"), buntdb.IndexJSON("age"))
  10. Set and Get key/values

    master

    To store a value, use tx.Set() within an Update transaction. To retrieve a value, use tx.Get() within a View transaction. If a key does not exist, tx.Get() returns an ErrNotFound error.

    // Setting a value
    err := db.Update(func(tx *buntdb.Tx) error {
    	_, _, err := tx.Set("mykey", "myvalue", nil)
    	return err
    })
    
    // Getting a value
    err := db.View(func(tx *buntdb.Tx) error {
    	val, err := tx.Get("mykey")
    	if err != nil {
    		return err
    	}
    	fmt.Printf("value is %s\n", val)
    	return nil
    })
  11. Iterate over keys and values

    master

    BuntDB stores keys in ascending order. You can iterate using various methods including Ascend, Descend, and range-based methods. The iterator function takes a callback that returns a boolean; return true to continue or false to stop.

    err := db.View(func(tx *buntdb.Tx) error {
    	err := tx.Ascend("", func(key, value string) bool {
    		fmt.Printf("key: %s, value: %s\n", key, value)
    		return true // continue iteration
    	})
    	return err
    })