DEV Community

Yusuf Turhan Papurcu for Golang

Posted on

Using BoltDB as internal database 💾

If you are looking for a small database for your fun project, I have something you might like. It is small, works as a key-value store and it's pure go.

What is Bolt?

Bolt is a pure Go key/value store inspired by Howard Chu's LMDB project. The goal of the project is to provide a simple, fast, and reliable database for projects that don't require a full database server such as Postgres or MySQL.

Since Bolt is meant to be used as such a low-level piece of functionality, simplicity is key. The API will be small and only focus on getting values and setting values. That's it.

How to use Bolt?

Installing

Bolt doesn't need any install other than go get. It just works as a library. So your only need is adding it to go.mod file.

go get github.com/boltdb/bolt

Creating database

After you can create your database like this.

    db, err := bolt.Open("my.db", 0600, &bolt.Options{})
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
Enter fullscreen mode Exit fullscreen mode

In here you can add timeout to your database. Or you can set readonly if you don't need writing into. Just set them in &bolt.Options{}.

Writing into database

You need to create bucket first. After than you can write your key/value data into bucket. Also tx.CreateBucketIfNotExists([]byte) function is life saver.

    db.Update(func(tx *bolt.Tx) error {
        bucket, err := tx.CreateBucketIfNotExists([]byte("todo"))
        if err != nil {
            return fmt.Errorf("create bucket: %s", err)
        }
        return bucket.Put([]byte("task-1"), []byte("Test BoltDB"))
    })
Enter fullscreen mode Exit fullscreen mode

If you have a bucket already you can write into it like this. Caution checking bucket is nil is important. Because if you try to use Put on nil bucket your program will panic.

    db.Update(func(tx *bolt.Tx) error {
        bucket := tx.Bucket([]byte("todo"))
        if bucket == nil {
            return fmt.Errorf("get bucket: FAILED")
        }
        return bucket.Put([]byte("task-1"), []byte("Test BoltDB additions"))
    })
Enter fullscreen mode Exit fullscreen mode

Querying data from database

Querying is as simple as writing. Just call your bucket and ask it for your data.

    db.View(func(tx *bolt.Tx) error {
        b := tx.Bucket([]byte("todo"))
        if b == nil {
            return fmt.Errorf("get bucket: FAILED")
        }
        fmt.Println(b.Get([]byte("task-1")))
        // should return nil to complete the transaction
        return nil
    })
Enter fullscreen mode Exit fullscreen mode

And here is simple way to iterate on all keys in one bucket.

    db.View(func(tx *bolt.Tx) error {
        b := tx.Bucket([]byte("todo"))
        if b == nil {
            return fmt.Errorf("get bucket: FAILED")
        }
        // we need cursor for iteration
        c := b.Cursor()
        for k, v := c.First(); k != nil; k, v = c.Next() {
            fmt.Println("Key: ", string(k), " Value: ", string(v))
        }
        // should return nil to complete the transaction
        return nil
    })
Enter fullscreen mode Exit fullscreen mode

Conclusion

  • Bolt is a pure Go key/value store
  • Bolt is native go library
  • Bolt is supported everywhere which go is supported
  • Creating, Writing and Querying inside Bolt is really easy.

Simple and powerful toolkit for BoltDB

Storm is a simple and powerful toolkit for BoltDB. Basically, Storm provides indexes, a wide range of methods to store and fetch data, an advanced query system, and much more.
GitHub: https://github.com/asdine/storm

Future Readings

Discussion (2)

Collapse
marcello_h profile image
Marcelloh

I personally like: /github.com/xujiajun/nutsdb
(faster than BoltDB)

Collapse
leningr1988 profile image
Lenin Guerrero

excellent article, I am implementing the Storm toolkit but, I have doubts about in which cases I should use buckets, what are they for, I think the documentation falls short and the other thing is that I am saving a struct that contains another struct, but I can not find data in the internal struct which I have as inline. Has anyone worked with this lib and knows how to make that query?