在本章中,我们将介绍以下配方:
每当我们想要持久化数据时,我们总是希望将其保存在数据库中,数据库主要分为两类:SQL和NoSQL。根据业务用例的不同,每个类别下都有许多数据库可供使用,因为每个数据库都有不同的特性和用途。
在本章中,我们将把一个 Go web 应用与最著名的开源数据库MySQL和MongoDB进行集成,并学习对它们执行 CRUD 操作。由于我们将使用 MySQL 和 MongoDB,我假设这两个数据库都已安装并运行在您的本地机器上。
假设您是一名开发人员,希望将应用数据保存在 MySQL 数据库中。作为第一步,您必须在应用和 MySQL 之间建立连接,我们将在本配方中介绍这一点
通过执行以下命令,验证 MySQL 是否在端口3306
上本地安装和运行:
$ ps -ef | grep 3306
这将返回以下响应:
另外,登录 MySQL 数据库并创建一个 mydb 数据库,执行如下屏幕截图所示的命令:
go get
命令安装github.com/go-sql-driver/mysql
包,如下所示:$ go get github.com/go-sql-driver/mysql
connect-mysql.go
。然后我们连接到 MySQL 数据库,进行SELECT
查询,得到当前的数据库名称,如下所示:package main
import
(
"database/sql"
"fmt"
"log"
"net/http"
"github.com/go-sql-driver/mysql"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
DRIVER_NAME = "mysql"
DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init()
{
db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
if connectionError != nil
{
log.Fatal("error connecting to database :: ", connectionError)
}
}
func getCurrentDb(w http.ResponseWriter, r *http.Request)
{
rows, err := db.Query("SELECT DATABASE() as db")
if err != nil
{
log.Print("error executing query :: ", err)
return
}
var db string
for rows.Next()
{
rows.Scan(&db)
}
fmt.Fprintf(w, "Current Database is :: %s", db)
}
func main()
{
http.HandleFunc("/", getCurrentDb)
defer db.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run connect-mysql.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
浏览http://localhost:8080/
会返回当前数据库名称,如下图所示:
让我们了解一下我们编写的程序:
我们使用import ( "database/sql" "fmt" "log" "net/http" _ "github.com/go-sql-driver/mysql")
导入github.com/go-sql-driver/mysql
是因为它的副作用或初始化,在 import 语句前面显式使用下划线。
使用var db *sql.DB
,我们声明了一个私有DB
实例。
根据项目大小,您可以全局声明 DB 实例,使用处理程序将其作为依赖项注入,或者将连接池指针放入x/net/context
。
init()
函数,在该函数中,我们连接到数据库,并向其传递数据库驱动程序名称和数据源。getCurrentDb
处理程序,它基本上对数据库执行一个 select 查询,以获取当前数据库名称,迭代记录,将其值复制到变量中,并最终将其写入 HTTP 响应流。在数据库中创建或保存记录需要我们编写 SQL 查询并执行它们,实现对象关系映射(ORM),或者实现数据映射技术。
在这个配方中,我们将编写一个 SQL 查询,并使用database/sql
包执行它来创建一个记录。为了实现这一点,您还可以使用 Go 中提供的许多第三方库中的任何库来实现 ORM,例如https://github.com/jinzhu/gorm
、https://github.com/go-gorp/gorp
和https://github.com/jirfag/go-queryset
。
由于我们在前面的配方中已经与 MySQL 数据库建立了连接,因此我们将扩展它以创建一个执行 SQL 查询的记录。
在创建记录之前,我们必须在 MySQL 数据库中创建一个表,我们将通过执行以下屏幕截图中所示的命令来实现这一点:
go get
命令安装github.com/go-sql-driver/mysql
和github.com/gorilla/mux
包,如下所示:$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
create-record-mysql.go
,然后连接 MySQL 数据库,进行插入查询,创建员工记录,如下图:package main
import
(
"database/sql"
"fmt"
"log"
"net/http"
"strconv"
"github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
DRIVER_NAME = "mysql"
DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init()
{
db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
if connectionError != nil
{
log.Fatal("error connecting to database : ", connectionError)
}
}
func createRecord(w http.ResponseWriter, r *http.Request)
{
vals := r.URL.Query()
name, ok := vals["name"]
if ok
{
log.Print("going to insert record in database for name : ",
name[0])
stmt, err := db.Prepare("INSERT employee SET name=?")
if err != nil
{
log.Print("error preparing query :: ", err)
return
}
result, err := stmt.Exec(name[0])
if err != nil
{
log.Print("error executing query :: ", err)
return
}
id, err := result.LastInsertId()
fmt.Fprintf(w, "Last Inserted Record Id is :: %s",
strconv.FormatInt(id, 10))
}
else
{
fmt.Fprintf(w, "Error occurred while creating record in
database for name :: %s", name[0])
}
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employee/create", createRecord).
Methods("POST")
defer db.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server : ", err)
return
}
}
$ go run create-record-mysql.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
从命令行执行POST
请求以创建员工记录,如下所示,将为您提供上次创建的记录的 ID:
$ curl -X POST http://localhost:8080/employee/create?name=foo
Last created record id is :: 1
让我们了解一下我们编写的程序:
import ("database/sql" "fmt" "log" "net/http" "strconv" _ "github.com/go-sql-driver/mysql" "github.com/gorilla/mux")
导入github.com/gorilla/mux
创建 Gorilla Mux 路由器,初始化 Go MySQL 驱动,导入github.com/go-sql-driver/mysql
包。createRecord
处理程序,它从请求中获取名称,将其分配给局部变量名称,准备一个带有名称占位符的INSERT
语句,该占位符将动态替换为名称,执行该语句,并最终将最后创建的 ID 写入 HTTP 响应流。在前面的方法中,我们在 MySQL 数据库中创建了一个雇员记录。现在,在这个配方中,我们将学习如何通过执行 SQL 查询来读取它。
go get
命令安装github.com/go-sql-driver/mysql
和github.com/gorilla/mux
包,如下所示:$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
read-record-mysql.go
连接到 MySQL 数据库,执行SELECT
查询,从数据库中获取所有员工,遍历记录,将其值复制到 struct 中,将所有员工添加到列表中,并将其写入 HTTP 响应流,如下所示:package main
import
(
"database/sql" "encoding/json"
"log"
"net/http"
"github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
DRIVER_NAME = "mysql"
DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init()
{
db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
if connectionError != nil
{
log.Fatal("error connecting to database :: ", connectionError)
}
}
type Employee struct
{
Id int `json:"uid"`
Name string `json:"name"`
}
func readRecords(w http.ResponseWriter, r *http.Request)
{
log.Print("reading records from database")
rows, err := db.Query("SELECT * FROM employee")
if err != nil
{
log.Print("error occurred while executing select
query :: ",err)
return
}
employees := []Employee{}
for rows.Next()
{
var uid int
var name string
err = rows.Scan(&uid, &name)
employee := Employee{Id: uid, Name: name}
employees = append(employees, employee)
}
json.NewEncoder(w).Encode(employees)
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employees", readRecords).Methods("GET")
defer db.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run read-record-mysql.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听。
浏览http://localhost:8080/employees
将列出员工表中的所有记录,如下图所示:
让我们看看我们编写的程序:
import ( "database/sql" "encoding/json" "log" "net/http" _ "github.com/go-sql-driver/mysql" "github.com/gorilla/mux")
,我们导入了一个额外的包encoding/json
,它有助于将 Go 数据结构编组到JSON
。Person
,它有Id
和Name
字段。请记住,字段名在类型定义中应以大写字母开头,否则可能会出现错误
readRecords
处理程序,它查询数据库以从 employee 表中获取所有记录,迭代记录,将其值复制到结构中,将所有记录添加到列表中,将对象列表封送到 JSON,并将其写入 HTTP 响应流。考虑一个场景,您为数据库中的雇员创建了一个记录,记录有所有的细节,如名称、部门、地址等,并且在一段时间之后,雇员更改部门。在这种情况下,我们必须在数据库中更新他们的部门,以便他们的详细信息在整个组织内同步,这可以通过使用SQL UPDATE
语句实现,在本配方中,我们将了解如何在 Go 中实现它。
go get
命令安装github.com/go-sql-driver/mysql
和github.com/gorilla/mux
包,如下所示:$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
update-record-mysql.go
。然后我们连接到 MySQL 数据库,更新员工的姓名作为 ID,并将数据库中更新的记录数写入 HTTP 响应流,如下所示:package main
import
(
"database/sql"
"fmt"
"log"
"net/http"
"github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
DRIVER_NAME = "mysql"
DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init()
{
db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
if connectionError != nil
{
log.Fatal("error connecting to database :: ", connectionError)
}
}
type Employee struct
{
Id int `json:"uid"`
Name string `json:"name"`
}
func updateRecord(w http.ResponseWriter, r *http.Request)
{
vars := mux.Vars(r)
id := vars["id"]
vals := r.URL.Query()
name, ok := vals["name"]
if ok
{
log.Print("going to update record in database
for id :: ", id)
stmt, err := db.Prepare("UPDATE employee SET name=?
where uid=?")
if err != nil
{
log.Print("error occurred while preparing query :: ", err)
return
}
result, err := stmt.Exec(name[0], id)
if err != nil
{
log.Print("error occurred while executing query :: ", err)
return
}
rowsAffected, err := result.RowsAffected()
fmt.Fprintf(w, "Number of rows updated in database
are :: %d",rowsAffected)
}
else
{
fmt.Fprintf(w, "Error occurred while updating record in
database for id :: %s", id)
}
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employee/update/{id}",
updateRecord).Methods("PUT")
defer db.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run update-record-mysql.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
接下来,从命令行执行一个PUT
请求,以更新 ID 为1
的员工记录,将给出数据库中更新的记录数作为响应:
$ curl -X PUT http://localhost:8080/employee/update/1?name\=bar
Number of rows updated in database are :: 1
让我们看看我们编写的程序:
updateRecord
处理程序,该处理程序将数据库中要更新的 ID 作为 URL 路径变量 path,将新名称作为请求变量,准备一个update
语句,其中名称和 UID 作为占位符,将动态替换该语句,执行该语句,获取执行后更新的行数,并将其写入 HTTP 响应流。gorilla/mux
路由器注册了一个updateRecord
处理程序,为每个PUT
请求调用 URL 模式/employee/update/{id}
,并在我们从main()
函数返回后使用defer db.Close()
语句关闭数据库。考虑一个雇员离开组织的情况,您想从数据库中撤消他们的详细信息。在这种情况下,我们可以使用SQL DELETE
语句,我们将在本配方中介绍它。
go get
命令安装github.com/go-sql-driver/mysql
和github.com/gorilla/mux
包,如下所示:$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
delete-record-mysql.go
。然后我们连接到 MySQL 数据库,从数据库中删除一名员工的姓名,并将从数据库中删除的记录数写入 HTTP 响应流,如下所示:package main
import
(
"database/sql"
"fmt"
"log"
"net/http"
"github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
DRIVER_NAME = "mysql"
DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init()
{
db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
if connectionError != nil
{
log.Fatal("error connecting to database :: ", connectionError)
}
}
func deleteRecord(w http.ResponseWriter, r *http.Request)
{
vals := r.URL.Query()
name, ok := vals["name"]
if ok
{
log.Print("going to delete record in database for
name :: ", name[0])
stmt, err := db.Prepare("DELETE from employee where name=?")
if err != nil
{
log.Print("error occurred while preparing query :: ", err)
return
}
result, err := stmt.Exec(name[0])
if err != nil
{
log.Print("error occurred while executing query :: ", err)
return
}
rowsAffected, err := result.RowsAffected()
fmt.Fprintf(w, "Number of rows deleted in database are :: %d",
rowsAffected)
}
else
{
fmt.Fprintf(w, "Error occurred while deleting record in
database for name %s", name[0])
}
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employee/delete",
deleteRecord).Methods("DELETE")
defer db.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run delete-record-mysql.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
接下来,从命令行执行一个DELETE
请求,删除一个名为bar
的员工,将得到从数据库中删除的记录数:
$ curl -X DELETE http://localhost:8080/employee/delete?name\=bar
Number of rows deleted in database are :: 1
让我们看看我们编写的程序:
deleteRecord
处理程序,它获取要从数据库中删除的名称作为请求变量,准备一个DELETE
语句,该语句的名称作为占位符,将被动态替换,执行该语句,获取执行后删除的行数,并将其写入 HTTP 响应流。gorilla/mux
路由器注册了一个deleteRecord
处理程序,为每个DELETE
请求调用 URL 模式/employee/delete
,并在main()
函数返回后使用defer db.Close()
语句关闭数据库。每当您想要在 MongoDB 数据库中持久化数据时,您必须采取的第一步是在数据库和您的 web 应用之间建立连接,我们将在本食谱中使用 Go-gopkg.in/mgo.v2
最著名和最常用的 MongoDB 驱动程序之一来介绍这一点。
通过执行以下命令,验证MongoDB
是否已安装并在端口27017
上本地运行:
$ mongo
这将返回以下响应:
go get
命令安装gopkg.in/mgo.v
包,如下所示:$ go get gopkg.in/mgo.v
connect-mongodb.go
。然后我们连接到MongoDB
数据库,从集群中获取所有数据库名称,并将它们写入 HTTP 响应流,如下所示:package main
import
(
"fmt"
"log"
"net/http"
"strings"
mgo "gopkg.in/mgo.v2"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
func init()
{
session, connectionError = mgo.Dial(MONGO_DB_URL)
if connectionError != nil
{
log.Fatal("error connecting to database :: ", connectionError)
}
session.SetMode(mgo.Monotonic, true)
}
func getDbNames(w http.ResponseWriter, r *http.Request)
{
db, err := session.DatabaseNames()
if err != nil
{
log.Print("error getting database names :: ", err)
return
}
fmt.Fprintf(w, "Databases names are :: %s", strings.Join
(db, ", "))
}
func main()
{
http.HandleFunc("/", getDbNames)
defer session.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run connect-mongodb.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
浏览到http://localhost:8080/
将列出 MongoDB 集群中存在的所有数据库的名称,如下图所示:
让我们看看我们编写的程序:
import ( "fmt" "log" "net/http" "strings" mgo "gopkg.in/mgo.v2" )
导入gopkg.in/mgo.v2
,包别名为mgo
。var session *mgo.Session
声明私有 MongoDBSession
实例,该实例充当与数据库的通信会话。var connectionError error
,我们声明了一个私有error
对象。init()
函数,其中我们连接到 MongoDB,将主机传递为127.0.0.1
,这意味着 MongoDB 和应用都在端口27017
的同一台机器上运行,可以选择将会话切换为单调行为,以便读取的数据在同一会话中的顺序查询中保持一致,在会话中所做的修改将在随后的查询中观察到。如果您的 MongoDB 运行在除27017
之外的端口上,那么您必须传递主机和端口,以冒号分隔,如:mgo.Dial("localhost:27018")
。
getDbNames
处理程序,它基本上从 MongoDB 集群获取所有数据库名称,并将它们作为逗号分隔的字符串写入 HTTP 响应流。在本教程中,我们将学习如何使用 Go 的 MongoDB 驱动程序(gopkg.In/mgo.v2)在数据库中创建 BSON 文档(类似 JSON 文档的二进制编码序列化)
go get
命令安装gopkg.in/mgo.v2
和github.com/gorilla/mux
包,如下所示:$ go get gopkg.in/mgo.v2
$ go get github.com/gorilla/mux
create-record-mongodb.go
。然后我们连接到 MongoDB 数据库,创建一个带有两个字段 ID 和 name 的 employee 文档,并将上次创建的文档 ID 写入 HTTP 响应流,如下所示:package main
import
(
"fmt"
"log"
"net/http"
"strconv"
"github.com/gorilla/mux"
mgo "gopkg.in/mgo.v2"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
type Employee struct
{
Id int `json:"uid"`
Name string `json:"name"`
}
func init()
{
session, connectionError = mgo.Dial(MONGO_DB_URL)
if connectionError != nil
{
log.Fatal("error connecting to database :: ", connectionError)
}
session.SetMode(mgo.Monotonic, true)
}
func createDocument(w http.ResponseWriter, r *http.Request)
{
vals := r.URL.Query()
name, nameOk := vals["name"]
id, idOk := vals["id"]
if nameOk && idOk
{
employeeId, err := strconv.Atoi(id[0])
if err != nil
{
log.Print("error converting string id to int :: ", err)
return
}
log.Print("going to insert document in database for name
:: ", name[0])
collection := session.DB("mydb").C("employee")
err = collection.Insert(&Employee{employeeId, name[0]})
if err != nil
{
log.Print("error occurred while inserting document in
database :: ", err)
return
}
fmt.Fprintf(w, "Last created document id is :: %s", id[0])
}
else
{
fmt.Fprintf(w, "Error occurred while creating document in
database for name :: %s", name[0])
}
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employee/create",
createDocument).Methods("POST")
defer session.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run create-record-mongodb.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
接下来,从命令行执行POST
请求以创建员工文档,如下所示,将为您提供在 MongoDB 中创建的文档的 ID:
$ curl -X POST http://localhost:8080/employee/create?name=foo\&id=1
Last created document id is :: 1
让我们看看我们编写的程序:
import ( "fmt" "log" "net/http" "strconv" "github.com/gorilla/mux" mgo "gopkg.in/mgo.v2")
导入github.com/gorilla/mux
创建 Gorilla Mux 路由器和gopkg.in/mgo.v2
,包别名为mgo
,作为 MongoDB 驱动。createDocument
处理程序,它从 HTTP 请求中获取员工的姓名和 ID。因为请求变量的类型为string
,所以我们将string
类型的变量 ID 转换为int
类型。然后,我们从 MongoDB 获取 employee 集合并调用collection.Insert
处理程序在数据库中保存Employee
结构类型的实例。在前面的配方中,我们在 MongoDB 中创建了一个 BSON 文档。现在,在这个配方中,我们将学习如何使用gopkg.in/mgo.v2/bson
包来阅读它,它有助于查询 MongoDB 集合。
go get
命令安装gopkg.in/mgo.v2
、gopkg.in/mgo.v2/bson
和github.com/gorilla/mux
包,如下所示:$ go get gopkg.in/mgo.v2
$ go get gopkg.in/mgo.v2/bson
$ go get github.com/gorilla/mux
read-record-mongodb.go
。然后我们连接到 MongoDB 数据库,读取员工集合中的所有文档,将列表封送到 JSON,并将其写入 HTTP 响应流,如下所示:package main
import
(
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
func init()
{
session, connectionError = mgo.Dial(MONGO_DB_URL)
if connectionError != nil
{
log.Fatal("error connecting to database :: ", connectionError)
}
session.SetMode(mgo.Monotonic, true)
}
type Employee struct
{
Id int `json:"uid"`
Name string `json:"name"`
}
func readDocuments(w http.ResponseWriter, r *http.Request)
{
log.Print("reading documents from database")
var employees []Employee
collection := session.DB("mydb").C("employee")
err := collection.Find(bson.M{}).All(&employees)
if err != nil
{
log.Print("error occurred while reading documents from
database :: ", err)
return
}
json.NewEncoder(w).Encode(employees)
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employees", readDocuments).Methods("GET")
defer session.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run read-record-mongodb.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听。
接下来,浏览到http://localhost:8080/employees
将为您提供 MongoDB 员工集合中所有员工的列表:
让我们看看我们在计划中引入的变化:
import ( "encoding/json" "log" "net/http" "github.com/gorilla/mux" mgo "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson")
,我们导入了一个额外的gopkg.in/mgo.v2/bson
包,它是 Go 的 BSON 规范,以及encoding/json
包,我们用于将从 MongoDB 获得的对象列表封送到JSON
。readDocuments
处理程序,首先从 MongoDB 获取 employee 集合,查询其中的所有文档,迭代文档以将其映射到Employee
结构的数组,最后将其封送到JSON
。一旦创建了 BSON 文档,我们可能需要更新它的一些字段。在这种情况下,我们必须对 MongoDB 集合执行update/upsert
查询,我们将在本配方中介绍。
go get
命令安装gopkg.in/mgo.v2
、gopkg.in/mgo.v2/bson
和github.com/gorilla/mux
包,如下所示:$ go get gopkg.in/mgo.v2
$ go get gopkg.in/mgo.v2/bson
$ go get github.com/gorilla/mux
update-record-mongodb.go
。然后我们连接到 MongoDB 数据库,更新员工的姓名以获取 ID,并将 MongoDB 中更新的记录数写入 HTTP 响应流,如下所示:package main
import
(
"fmt"
"log"
"net/http"
"strconv"
"github.com/gorilla/mux"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
type Employee struct
{
Id int `json:"uid"`
Name string `json:"name"`
}
func init()
{
session, connectionError = mgo.Dial(MONGO_DB_URL)
if connectionError != nil
{
log.Fatal("error connecting to database :: ",
connectionError)
}
session.SetMode(mgo.Monotonic, true)
}
func updateDocument(w http.ResponseWriter, r *http.Request)
{
vars := mux.Vars(r)
id := vars["id"]
vals := r.URL.Query()
name, ok := vals["name"]
if ok
{
employeeId, err := strconv.Atoi(id)
if err != nil
{
log.Print("error converting string id to int :: ", err)
return
}
log.Print("going to update document in database
for id :: ", id)
collection := session.DB("mydb").C("employee")
var changeInfo *mgo.ChangeInfo
changeInfo, err = collection.Upsert(bson.M{"id": employeeId},
&Employee{employeeId, name[0]})
if err != nil
{
log.Print("error occurred while updating record in
database :: ", err)
return
}
fmt.Fprintf(w, "Number of documents updated in database
are :: %d", changeInfo.Updated)
}
else
{
fmt.Fprintf(w, "Error occurred while updating document
in database for id :: %s", id)
}
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employee/update/{id}",
updateDocument).Methods("PUT")
defer session.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run update-record-mongodb.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
接下来,从命令行执行对UPDATE
员工文档的PUT
请求,如下所示,将为您提供 MongoDB 中更新的文档数量:
$ curl -X PUT http://localhost:8080/employee/update/1\?name\=bar
Number of documents updated in database are :: 1
让我们看看我们编写的程序:
updateDocument
处理程序,它将在 MongoDB 中更新的 ID 作为 URL 路径变量,将新名称作为 HTTP 请求变量。由于请求变量是字符串类型,我们已经将变量 IDstring
类型转换为int
类型。然后,我们从 MongoDB 获取 employee 集合,如果不存在,则调用collection.Upsert
处理程序进行插入,或者使用所提供 ID 的新名称更新员工文档。updateDocument
处理程序,在gorilla/mux
路由器上为每个PUT
请求调用 URL 模式/employee/update/{id}
,并在从main()
函数返回后使用defer session.Close()
语句关闭 MongoDB 会话。每当我们想要清理数据库或删除不再需要的文档时,我们都可以使用 MongoDB gopkg 驱动程序(gopkg.in/mgo.v2)轻松删除它们,我们将在本配方中介绍这一点。
go get
命令安装gopkg.in/mgo.v2
、gopkg.in/mgo.v2/bson
和github.com/gorilla/mux
包,如下所示:$ go get gopkg.in/mgo.v2
$ go get gopkg.in/mgo.v2/bson
$ go get github.com/gorilla/mux
delete-record-mongodb.go
。然后我们连接到 MongoDB,获取要从数据库中删除的员工的姓名作为 HTTP 请求变量,获取命名集合,然后删除文档,如下所示:package main
import
(
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
const
(
CONN_HOST = "localhost"
CONN_PORT = "8080"
MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
type Employee struct
{
Id int `json:"uid"`
Name string `json:"name"`
}
func init()
{
session, connectionError = mgo.Dial(MONGO_DB_URL)
if connectionError != nil
{
log.Fatal("error connecting to database :: ",
connectionError)
}
session.SetMode(mgo.Monotonic, true)
}
func deleteDocument(w http.ResponseWriter, r *http.Request)
{
vals := r.URL.Query()
name, ok := vals["name"]
if ok
{
log.Print("going to delete document in database for
name :: ", name[0])
collection := session.DB("mydb").C("employee")
removeErr := collection.Remove(bson.M{"name": name[0]})
if removeErr != nil
{
log.Print("error removing document from
database :: ", removeErr)
return
}
fmt.Fprintf(w, "Document with name %s is deleted from
database", name[0])
}
else
{
fmt.Fprintf(w, "Error occurred while deleting document
in database for name :: %s", name[0])
}
}
func main()
{
router := mux.NewRouter()
router.HandleFunc("/employee/delete",
deleteDocument).Methods("DELETE")
defer session.Close()
err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
if err != nil
{
log.Fatal("error starting http server :: ", err)
return
}
}
$ go run delete-record-mongodb.go
一旦我们运行程序,HTTP 服务器将在端口8080
上开始本地侦听
接下来,执行从命令行删除 BSON 文档的DELETE
请求,如下所示,将为您提供从数据库中删除的文档的名称:
$ curl -X DELETE http://localhost:8080/employee/delete?name\=bar
Document with name bar is deleted from database
让我们看看我们编写的程序:
deleteDocument
处理程序,该处理程序从 MongoDB 获取要删除的名称作为请求变量,从 MongoDB 获取 employee 集合,并调用collection.Remove
处理程序删除给定名称的文档。deleteDocument
处理程序,在gorilla/mux
路由器上为每个DELETE
请求调用 URL 模式/employee/delete
,并在main()
函数返回后使用defer session.Close()
语句关闭 MongoDB 会话。