Go实战--golang中使用RethinkDB(gorethink/gorethink.v3)

生命不止,继续go go go !!!

关于golang中操作数据库,曾经介绍了不少:

Go实战–go语言操作sqlite数据库(The way to go) Go实战–go语言操作MySQL数据库(go-sql-driver/mysql)

Go实战–golang中使用redis(redigo和go-redis/redis) Go实战–golang中使用MongoDB(mgo)

今天继续跟大家一起学习分享另一种数据库叫 RethinkDB。

RethinkDB

RethinkDB 是一个主要用来存储 JSON 文档的数据库引擎(MongoDB 存储的是 BSON),可以轻松和多个节点连成分布式数据库,非常好用的查询语言以及支持表的 joins 和 group by 操作等,其实跟mongodb类似。

RethinkDB pushes JSON to your apps in realtime. When your app polls for data, it becomes slow, unscalable, and cumbersome to maintain. RethinkDB is the open-source, scalable database that makes building realtime apps dramatically easier.

What is RethinkDB? RethinkDB is the first open-source, scalable JSON database built from the ground up for the realtime web. It inverts the traditional database architecture by exposing an exciting new access model – instead of polling for changes, the developer can tell RethinkDB to continuously push updated query results to applications in realtime. RethinkDB’s realtime push architecture dramatically reduces the time and effort necessary to build scalable realtime apps.

In addition to being designed from the ground up for realtime apps, RethinkDB offers a flexible query language, intuitive operations and monitoring APIs, and is easy to setup and learn.

官网 https://www.rethinkdb.com/

Windows下安装 下载地址: https://www.rethinkdb.com/docs/install/windows/

解压

创建数据目录: d:\RethinkDB\data\

运行命令:

rethinkdb.exe -d d:\RethinkDB\data\

成功

In recursion: removing file 'd:\RethinkDB\data\\tmp'
warn: Trying to delete non-existent file 'd:\RethinkDB\data\\tmp'
Initializing directory d:\RethinkDB\data\
Running rethinkdb 2.3.6-windows (MSC 190024215)...
Running on 6.2.9200 (Windows 8, Server 2012)
Loading data from directory d:\RethinkDB\data\
Listening for intracluster connections on port 29015
Listening for client driver connections on port 28015
Listening for administrative HTTP connections on port 8080
Listening on cluster address: 127.0.0.1
Listening on driver address: 127.0.0.1
Listening on http address: 127.0.0.1
To fully expose RethinkDB on the network, bind to all addresses by running rethinkdb with the `--bind all` command line option.
Server ready, "LAPTOP_MNU6522J_xsq" b8612d2e-7c2b-4511-b85a-17468d91bf6d

可视化 http://localhost:8080

GoRethink - RethinkDB Driver for Go

github地址: https://github.com/GoRethink/gorethink

Star: 1253

获取:

go get gopkg.in/gorethink/gorethink.v3

文档地址: https://godoc.org/github.com/GoRethink/gorethink

ConnectOpts

type ConnectOpts struct {

    Address string `gorethink:"address,omitempty"`

    Addresses []string `gorethink:"addresses,omitempty"`

    Database string `gorethink:"database,omitempty"`

    Username string `gorethink:"username,omitempty"`

    Password string `gorethink:"password,omitempty"`

    AuthKey string `gorethink:"authkey,omitempty"`

    Timeout time.Duration `gorethink:"timeout,omitempty"`

    WriteTimeout time.Duration `gorethink:"write_timeout,omitempty"`

    ReadTimeout time.Duration `gorethink:"read_timeout,omitempty"`

    KeepAlivePeriod time.Duration `gorethink:"keep_alive_timeout,omitempty"`

    TLSConfig *tls.Config `gorethink:"tlsconfig,omitempty"`

    HandshakeVersion HandshakeVersion `gorethink:"handshake_version,omitempty"`

    UseJSONNumber bool

    NumRetries int

    InitialCap int `gorethink:"initial_cap,omitempty"`

    MaxOpen int `gorethink:"max_open,omitempty"`

    DiscoverHosts bool `gorethink:"discover_hosts,omitempty"`

    HostDecayDuration time.Duration

    NodeRefreshInterval time.Duration `gorethink:"node_refresh_interval,omitempty"`

    MaxIdle int `gorethink:"max_idle,omitempty"`
}

func Connect Connect creates a new database session.

func Connect(opts ConnectOpts) (*Session, error)

func Expr Expr converts any value to an expression and is also used by many other terms such as Insert and Update. This function can convert the following basic Go types (bool, int, uint, string, float) and even pointers, maps and structs.

func Expr(val interface{}) Term

func (Term) Run

func (t Term) Run(s QueryExecutor, optArgs ...RunOpts) (*Cursor, error)

Run runs a query using the given connection.

func (*Cursor) One

func (c *Cursor) One(result interface{}) error

One retrieves a single document from the result set into the provided slice and closes the cursor.

func DB

func DB(args ...interface{}) Term

DB references a database.

func TableDrop

func TableDrop(args ...interface{}) Term

TableDrop deletes a table. The table and all its data will be deleted.

func TableCreate

func TableCreate(name interface{}, optArgs ...TableCreateOpts) Term

TableCreate creates a table. A RethinkDB table is a collection of JSON documents.

官方例子 main.go

package main

import (
    "fmt"
    "log"

    r "gopkg.in/gorethink/gorethink.v3"
)

func main() {
    session, err := r.Connect(r.ConnectOpts{
        Address: "localhost:28015",
    })
    if err != nil {
        log.Fatalln(err)
    }

    res, err := r.Expr("Hello World").Run(session)
    if err != nil {
        log.Fatalln(err)
    }

    var response string
    err = res.One(&response)
    if err != nil {
        log.Fatalln(err)
    }

    fmt.Println(response)
}

如果rethinkdb服务没有开启则: 2017/12/12 14:37:34 gorethink: dial tcp [::1]:28015: connectex: No connection could be made because the target machine actively refused it.

开启后运行: Hello World

rethinkdb应用

访问: http://localhost:8080/#tables 创建一个database,命名为players

读写数据库

package main

import (
    "fmt"
    "log"
    "math/rand"
    "strconv"
    "time"

    r "gopkg.in/gorethink/gorethink.v3"
)

//ScoreEntry for scores
type ScoreEntry struct {
    ID         string `gorethink:"id,omitempty"`
    PlayerName string
    Score      int
}

func main() {
    fmt.Println("Connecting to RethinkDB: localhost:28015")

    session, err := r.Connect(r.ConnectOpts{
        Address:  "localhost:28015",
        Database: "players",
    })

    if err != nil {
        log.Fatal("Could not connect")
    }

    err = r.DB("players").TableDrop("scores").Exec(session)
    err = r.DB("players").TableCreate("scores").Exec(session)
    if err != nil {
        log.Fatal("Could not create table")
    }

    err = r.DB("players").Table("scores").IndexCreate("Score").Exec(session)
    if err != nil {
        log.Fatal("Could not create index")
    }

    for i := 0; i < 1000; i++ {
        player := new(ScoreEntry)
        player.ID = strconv.Itoa(i)
        player.PlayerName = fmt.Sprintf("Player %d", i)
        player.Score = rand.Intn(100)
        _, err := r.Table("scores").Insert(player).RunWrite(session)
        if err != nil {
            log.Fatal(err)
        }
    }

    for {
        var scoreentry ScoreEntry
        pl := rand.Intn(1000)
        sc := rand.Intn(6) - 2
        res, err := r.Table("scores").Get(strconv.Itoa(pl)).Run(session)
        if err != nil {
            log.Fatal(err)
        }

        err = res.One(&scoreentry)
        scoreentry.Score = scoreentry.Score + sc
        _, err = r.Table("scores").Update(scoreentry).RunWrite(session)
        time.Sleep(100 * time.Millisecond)
    }
}

可以通过localhost:8080可视化查看:

RethinkDB的CRUD

再来一个比较复杂的例子,代码结构会更好一点: bookmarket_store.go 其中包括了: create update Delete getAll GetByID

package main

import (
    "time"

    r "gopkg.in/gorethink/gorethink.v3"
)

// Bookmark type reperesents the metadata of a bookmark.
type Bookmark struct {
    ID                          string `gorethink:"id,omitempty" json:"id"`
    Name, Description, Location string
    Priority                    int // Priority (1 -5)
    CreatedOn                   time.Time
    Tags                        []string
}

// BookmarkStore provides CRUD operations against the Table "bookmarks".
type BookmarkStore struct {
    Session *r.Session
}

// Create inserts the value of struct Bookmark into Table.
func (store BookmarkStore) Create(b *Bookmark) error {

    resp, err := r.Table("bookmarks").Insert(b).RunWrite(store.Session)
    if err == nil {
        b.ID = resp.GeneratedKeys[0]
    }

    return err
}

// Update modifies an existing value of a Table.
func (store BookmarkStore) Update(b Bookmark) error {

    var data = map[string]interface{}{
        "description": b.Description,
        "location":    b.Location,
        "priority":    b.Priority,
        "tags":        b.Tags,
    }
    // partial update on RethinkDB
    _, err := r.Table("bookmarks").Get(b.ID).Update(data).RunWrite(store.Session)
    return err
}

// Delete removes an existing value from the Table.
func (store BookmarkStore) Delete(id string) error {
    _, err := r.Table("bookmarks").Get(id).Delete().RunWrite(store.Session)
    return err
}

// GetAll returns all documents from the Table.
func (store BookmarkStore) GetAll() ([]Bookmark, error) {
    bookmarks := []Bookmark{}

    res, err := r.Table("bookmarks").OrderBy("priority", r.Desc("createdon")).Run(store.Session)
    err = res.All(&bookmarks)
    return bookmarks, err
}

// GetByID returns single document from the Table.
func (store BookmarkStore) GetByID(id string) (Bookmark, error) {
    var b Bookmark
    res, err := r.Table("bookmarks").Get(id).Run(store.Session)
    res.One(&b)
    return b, err
}

main.go

package main

import (
    "fmt"
    "log"
    "time"

    r "gopkg.in/gorethink/gorethink.v3"
)

var store BookmarkStore
var id string

func initDB(session *r.Session) {
    var err error
    // Create Database
    _, err = r.DBCreate("bookmarkdb").RunWrite(session)
    if err != nil {
        log.Fatalf("[initDB]: %s\n", err)
    }
    // Create Table
    _, err = r.DB("bookmarkdb").TableCreate("bookmarks").RunWrite(session)
    if err != nil {
        log.Fatalf("[initDB]: %s\n", err)
    }
}

func changeFeeds(session *r.Session) {
    bookmarks, err := r.Table("bookmarks").Changes().Field("new_val").Run(session)
    if err != nil {
        log.Fatalf("[changeFeeds]: %s\n", err)
    }
    // Luanch a goroutine to print real-time updates.
    go func() {
        var bookmark Bookmark
        for bookmarks.Next(&bookmark) {
            if bookmark.ID == "" { // for delete, new_val will be null.
                fmt.Println("Real-time update: Document has been deleted")
            } else {
                fmt.Printf("Real-time update: Name:%s, Description:%s, Priority:%d\n",
                    bookmark.Name, bookmark.Description, bookmark.Priority)
            }
        }
    }()
}

func init() {
    session, err := r.Connect(r.ConnectOpts{
        Address:  "localhost:28015",
        Database: "bookmarkdb",
        MaxIdle:  10,
        MaxOpen:  10,
    })

    if err != nil {
        log.Fatalf("[RethinkDB Session]: %s\n", err)
    }
    r.Table("bookmarks").Delete().Run(session)
    // Create Database and Table.
    initDB(session)
    store = BookmarkStore{
        Session: session,
    }
    // Subscribe real-time changes
    changeFeeds(session)
}

func createUpdate() {
    bookmark := Bookmark{
        Name:        "mgo",
        Description: "Go driver for MongoDB",
        Location:    "https://github.com/go-mgo/mgo",
        Priority:    1,
        CreatedOn:   time.Now(),
        Tags:        []string{"go", "nosql", "mongodb"},
    }
    // Insert a new document.
    if err := store.Create(&bookmark); err != nil {
        log.Fatalf("[Create]: %s\n", err)
    }
    id = bookmark.ID
    fmt.Printf("New bookmark has been inserted with ID: %s\n", id)
    // Retrieve the updated document.
    bookmark.Priority = 2
    if err := store.Update(bookmark); err != nil {
        log.Fatalf("[Update]: %s\n", err)
    }
    fmt.Println("The value after update:")
    // Retrieve an existing document by id.
    getByID(id)
    bookmark = Bookmark{
        Name:        "gorethink",
        Description: "Go driver for RethinkDB",
        Location:    "https://github.com/dancannon/gorethink",
        Priority:    1,
        CreatedOn:   time.Now(),
        Tags:        []string{"go", "nosql", "rethinkdb"},
    }
    // Insert a new document.
    if err := store.Create(&bookmark); err != nil {
        log.Fatalf("[Create]: %s\n", err)
    }
    id = bookmark.ID
    fmt.Printf("New bookmark has been inserted with ID: %s\n", id)

}

func getByID(id string) {
    bookmark, err := store.GetByID(id)
    if err != nil {
        log.Fatalf("[GetByID]: %s\n", err)
    }
    fmt.Printf("Name:%s, Description:%s, Priority:%d\n", bookmark.Name, bookmark.Description, bookmark.Priority)
}

func getAll() {
    // Layout for formatting dates.
    layout := "2006-01-02 15:04:05"
    // Retrieve all documents.
    bookmarks, err := store.GetAll()
    if err != nil {
        log.Fatalf("[GetAll]: %s\n", err)
    }
    fmt.Println("Read all documents")
    for _, v := range bookmarks {
        fmt.Printf("Name:%s, Description:%s, Priority:%d, CreatedOn:%s\n", v.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))
    }

}

func delete() {
    if err := store.Delete(id); err != nil {
        log.Fatalf("[Delete]: %s\n", err)
    }
    bookmarks, err := store.GetAll()
    if err != nil {
        log.Fatalf("[GetAll]: %s\n", err)
    }
    fmt.Printf("Number of documents in the table after delete:%d\n", len(bookmarks))
}

func main() {
    createUpdate()
    getAll()
    delete()
}

输出:

Real-time update: Name:mgo, Description:Go driver for MongoDB, Priority:1
New bookmark has been inserted with ID: 1f98916d-a5d5-400b-828e-8a53d4193521
Real-time update: Name:mgo, Description:Go driver for MongoDB, Priority:2
The value after update:
Name:mgo, Description:Go driver for MongoDB, Priority:1
Real-time update: Name:gorethink, Description:Go driver for RethinkDB, Priority:1
New bookmark has been inserted with ID: 0da9d082-265c-40e8-af54-7210a78cdb19
Read all documents
Name:gorethink, Description:Go driver for RethinkDB, Priority:1, CreatedOn:2017-12-12 15:10:13
Name:mgo, Description:Go driver for MongoDB, Priority:2, CreatedOn:2017-12-12 15:10:13
Real-time update: Document has been deleted
Number of documents in the table after delete:1

悲伤的消息

Today(OCTOBER 05, 2016) I have sad news to share. After more than seven years of development, the company behind RethinkDB is shutting down. We worked very hard to make RethinkDB successful, but in spite of all our efforts we were ultimately unable to build a sustainable business. There is a lot of information to unpack – over the next few months, I’ll write about lessons learned so the startup community can benefit from our mistakes.

如何评价RethinkDB公司倒闭? https://www.zhihu.com/question/51345388?sort=created

尾声: RethinkDB: why we failed 结论: Pick a large market but build for specific users. Learn to recognize the talents you’re missing, then work like hell to get them on your team. Read The Economist religiously. It will make you better faster.

原文发布于微信公众号 - 程序员的酒和故事(cppdabaojian)

原文发表时间:2017-12-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

DataSet与Xml相互转化

string sql = "Select Top 10 F_ID,F_Name From T_Product";             DataSet Ds...

16010
来自专栏上善若水

004-golang 正则表达式的使用

1718
来自专栏ASP.NET MVC5 后台权限管理系统

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(10)-系统菜单栏[附源码]

似乎我们需要更多的模块了,我们有一个样例程序,可以帮助我们以后的系统开发做很多对照,我们稍后还有系统日志和系统异常的记录,这时浏览发生了困难,我们这一节来完成一...

2569
来自专栏韩东吉的Unity杂货铺

零基础入门 29:贴图变灰

今天的内容不多,通常在游戏中,大家经常会遇到这样的需求,就是原本一个美术出来的图片,因为某种状态下,需要将他变成灰色代表当前禁用或者未激活一类的提示效果,那么,...

563
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(7)-MVC与EasyUI DataGrid

本节知识点 为了符合后面更新后的重构系统,文章于2016-11-1日重写 EasyUI读取MVC后台Json数据 开始实现 我们的系统似乎越来越有趣了 首先...

2946
来自专栏c#开发者

Simulate a Windows Service using ASP.NET to run scheduled jobs

Introduction How to run scheduled jobs from ASP.NET without requiring a Windows ...

3667
来自专栏菩提树下的杨过

Flash/Flex学习笔记(14):制作涂鸦板

关键点:知道如何画线就行了,代码不复杂,直接看吧(从同事一本书上抄的) var drawing:Boolean; Mouse.hide(); //隐藏默认的光...

17810
来自专栏更流畅、简洁的软件开发方式

【开源】QuickPager ASP.NET2.0分页控件V2.0.0.6 修改了几个小bug,使用演示。

     由于项目里面还在使用vs2003,还没有使用新的分页控件,所以对新的分页控件的测试还很不到位,遗留了不少的bug,感谢网友试用提出宝贵意见。由于项目正...

2025
来自专栏运维

DELL R710 服务器内存排错

man dmidecode 可以得到详细的介绍和使用方法,dmidecode - DMI table decoder,DMI (Desktop Manageme...

512
来自专栏跟着阿笨一起玩NET

Winfrom 如何安全简单的跨线程更新控件

来源:http://www.cnblogs.com/rainbowzc/archive/2010/09/29/1838788.html

391

扫码关注云+社区