Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

A lightweight document-oriented NoSQL database written in pure Golang.

License

NotificationsYou must be signed in to change notification settings

ostafen/clover

Repository files navigation

CloverDB LogoCloverDB Logo

Lightweight document-oriented NoSQL Database

Mentioned in Awesome Go
Go ReferenceGo Report CardLicense: MITCoverage StatusJoin the chat at https://gitter.im/cloverDB/community

🇬🇧 English |🇨🇳 简体中文 |🇪🇸 Spanish

CloverDB is a lightweight NoSQL database designed for being simple and easily maintainable, thanks to its small code base. It has been inspired bytinyDB.

Features

  • Document oriented
  • Written in pure Golang
  • Simple and intuitive api
  • Easily maintainable

Why CloverDB?

CloverDB has been written for being easily maintainable. As such, it trades performance with simplicity, and is not intended to be an alternative to more performant databases such asMongoDB orMySQL.However, there are projects where running a separate database server may result overkilled, and, for simple queries, network delay may be the major performance bottleneck.For such scenarios,CloverDB may be a more suitable alternative.

Database Layout

Previously,CloverDB relied on theBadger key-value store as a storage layer. However,Badger is not suitable for every scenario (for example, when the database size is a constraint). This is why, the storage layer ofCloverDB has been abstracted through a set of interface types to work with any key-value store. At the moment,CloverDB can work with bothBadger andBolt (by defaultBolt is used).

Installation

Make sure you have a working Go environment (Go 1.18 or higher is required).

  GO111MODULE=on go get github.com/ostafen/clover/v2

Databases and Collections

CloverDB stores data records as JSON documents, which are grouped together in collections. A database is made up of one or more collections.

Database

To store documents inside collections, you have to open a Clover database using theOpen() function.

import ("log""github.com/dgraph-io/badger/v4"  c"github.com/ostafen/clover"  badgerstore"github.com/ostafen/clover/v2/store/badger")...// by default, Bolt will be used internallydb,_:=c.Open("clover-db")// use OpenWithStore() if you want to select a different storage backendstore,_:=badgerstore.Open(badger.DefaultOptions("").WithInMemory(true))// opens a badger in memory databasedb,_:=c.OpenWithStore(store)deferdb.Close()// remember to close the db when you have done

Collections

CloverDB stores documents inside collections. Collections are theschemaless equivalent of tables in relational databases. A collection is created by calling theCreateCollection() function on a database instance. New documents can be inserted using theInsert() orInsertOne() methods. Each document is uniquely identified by aVersion 4 UUID stored in the_id special field and generated during insertion.

db,_:=c.Open("clover-db")db.CreateCollection("myCollection")// create a new collection named "myCollection"// insert a new document inside the collectiondoc:=c.NewDocument()doc.Set("hello","clover!")// InsertOne returns the id of the inserted documentdocId,_:=db.InsertOne("myCollection",doc)fmt.Println(docId)

Importing and Exporting Collections

CloverDB is capable of easily importing and exporting collections to JSON format regardless of the storage engine used.

// dump the content of the "todos" collection in a "todos.json" filedb.ExportCollection("todos","todos.json")...// recover the todos collection from the exported json filedb.DropCollection("todos")db.ImportCollection("todos","todos.json")docs,_:=db.FindAll(c.NewQuery("todos"))for_,doc:=rangedocs {log.Println(doc)}

Queries

CloverDB is equipped with a fluent and elegant API to query your data. A query is represented by theQuery object, which allows to retrieve documents matching a givencriterion. A query can be created by passing a valid collection name to theQuery() method.

Select All Documents in a Collection

TheFindAll() method is used to retrieve all documents satisfying a given query.

docs,_:=db.FindAll(c.NewQuery("myCollection"))todo:=&struct {Completedbool`clover:"completed"`Titlestring`clover:"title"`UserIdint`clover:"userId"`}{}for_,doc:=rangedocs {doc.Unmarshal(todo)log.Println(todo)}

Filter Documents with Criteria

In order to filter the documents returned byFindAll(), you have to specify a query Criteria using theWhere() method. A Criteria object simply represents a predicate on a document, evaluating totrue only if the document satisfies all the query conditions.

The following example shows how to build a simple Criteria, matching all the documents having thecompleted field equal to true.

db.FindAll(c.NewQuery("todos").Where(c.Field("completed").Eq(true)))// or equivalentlydb.FindAll(c.NewQuery("todos").Where(c.Field("completed").IsTrue()))

In order to build very complex queries, we chain multiple Criteria objects by using theAnd() andOr() methods, each returning a new Criteria obtained by applying the corresponding logical operator.

// find all completed todos belonging to users with id 5 and 8db.FindAll(c.NewQuery("todos").Where(c.Field("completed").Eq(true).And(c.Field("userId").In(5,8))))

Naturally, you can also create Criteria involving multiple fields. CloverDB provides you with two equivalent ways to accomplish this:

db.FindAll(c.NewQuery("myCollection").Where(c.Field("myField1").Gt(c.Field("myField2"))))// or, if you preferdb.FindAll(c.NewQuery("myCollection").Where(c.Field("myField1").Gt("$myField2")))

Sorting Documents

To sort documents in CloverDB, you need to useSort(). It is a variadic function which accepts a sequence of SortOption, each allowing to specify a field and a sorting direction.A sorting direction can be one of 1 or -1, respectively corresponding to ascending and descending order. If no SortOption is provided,Sort() uses the_id field by default.

// Find any todo belonging to the most recent inserted userdb.FindFirst(c.NewQuery("todos").Sort(c.SortOption{"userId",-1}))

Skip/Limit Documents

Sometimes, it can be useful to discard some documents from the output, or simply set a limit on the maximum number of results returned by a query. For this purpose, CloverDB provides theSkip() andLimit() functions, both accepting an integer$n$ as parameter.

// discard the first 10 documents from the output,// also limiting the maximum number of query results to 100db.FindAll(c.NewQuery("todos").Skip(10).Limit(100))

Update/Delete Documents

TheUpdate() method is used to modify specific fields of documents in a collection. TheDelete() method is used to delete documents. Both methods belong to the Query object, so that it is easy to update and delete documents matching a particular query.

// mark all todos belonging to user with id 1 as completedupdates:=make(map[string]interface{})updates["completed"]=truedb.Update(c.NewQuery("todos").Where(c.Field("userId").Eq(1)),updates)// delete all todos belonging to users with id 5 and 8db.Delete(c.NewQuery("todos").Where(c.Field("userId").In(5,8)))

To update or delete a single document using a specific document id, useUpdateById() orDeleteById(), respectively:

docId:="1dbce353-d3c6-43b3-b5a8-80d8d876389b"// update the document with the specified iddb.UpdateById("todos",docId,map[string]interface{}{"completed":true})// or delete itdb.DeleteById("todos",docId)

Indexes

In CloverDB, indexes support the efficient execution of queries. Without indexes, a collection must be fully scanned to select those documents matching a given query. An index is a special data structure storing the values of a specific document field (or set of fields), sorted by the value of the field itself. This means that they can be exploited to supports efficient equality matches and range-based queries.Moreover, when documents are iterated through an index, results can be returned in sorted order without performing any additional sorting step.Note however that using indexes is not completely for free. Apart from increasing disk space, indexes require additional cpu-time during each insert and update/delete operation. Moreover, when accessing a document through an index, two disk reads must be performed, since indexes only store a reference (the document id) to the actual document. As a consequence, the speed-up is sensitive only when the specified criteria is used to access a restricted set of documents.

Creating an index

Currently, CloverDB only support single-field indexes. An index can be created simply by calling theCreateIndex() method, which takes both the names of the collection and the field to be indexed.

db.CreateIndex("myCollection","myField")

Assume you have the following query:

criteria:=c.Field("myField").Gt(a).And(c.Field("myField").Lt(b))db.FindAll(c.NewQuery("myCollection").Where(criteria).Sort(c.SortOption{"myField",-1}))

wherea andb are values of your choice. CloverDB will use the created index both to perform the range query and to return results in sorted order.

Data Types

Internally, CloverDB supports the following primitive data types:int64,uint64,float64,string,bool andtime.Time. When possible, values having different types are silently converted to one of the internal types: signed integer values get converted to int64, while unsigned ones to uint64. Float32 values are extended to float64.

For example, consider the following snippet, which sets an uint8 value on a given document field:

doc:=c.NewDocument()doc.Set("myField",uint8(10))// "myField" is automatically promoted to uint64fmt.Println(doc.Get("myField").(uint64))

Pointer values are dereferenced until eithernil or anon-pointer value is found:

varxint=10varptr*int=&xvarptr1**int=&ptrdoc.Set("ptr",ptr)doc.Set("ptr1",ptr1)fmt.Println(doc.Get("ptr").(int64)==10)fmt.Println(doc.Get("ptr1").(int64)==10)ptr=nildoc.Set("ptr1",ptr1)// ptr1 is not nil, but it points to the nil "ptr" pointer, so the field is set to nilfmt.Println(doc.Get("ptr1")==nil)

Invalid types leaves the document untouched:

doc:=c.NewDocument()doc.Set("myField",make(chanstruct{}))log.Println(doc.Has("myField"))// will output false

Contributing

CloverDB is actively developed. Any contribution, in the form of a suggestion, bug report or pull request, is well accepted 😊

Contributions and suggestions have been gratefully received from the following users:

Made withcontrib.rocks.


[8]ページ先頭

©2009-2025 Movatter.jp