与上下文一起使用mgo [英] Using mgo with context

查看:171
本文介绍了与上下文一起使用mgo的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在使用mgo作为我的API,但我在MongoDB中看到很多当前连接(使用少于5个设备进行测试)。通过在我的Mongo服务器中执行 db.serverStatus().connections 得到: {current:641,available:838219,totalCreated :1136} 。下面我在mgo的Github上抄录我的问题( Issue#429 ): p>

我正确地使用web服务器中的mgo吗?如果没有,你能给我一个完整的例子吗?



这段代码不起作用,把它看作几乎是伪代码(因为像导入这样的缺失部分,配置来自和模型),但它正是我如何使用mgo。



我必须说明我正在构建一个由几个移动设备和webapps。



main.go

  func main(){
mongoDBDialInfo:=& mgo.DialInfo {
Addrs:[] string {config.DatabaseURL},
超时:60 * time.Second,
数据库:config.DatabaseName,
用户名:config.DatabaseUsername,
密码:config.DatabasePassword,
}
$ b $ db,err:= mgo.DialWithInfo(mongoDBDialInfo)

if err!= nil {
log.Fatal(不能拨号Mongo:,err)
}

defer db.Close()
db.SetMode(mgo.Monotonic,true)

phoneIndex:= mgo.Index {
Key:[] string {pp},
Unique:true,
DropDups:true,
背景:true,
稀疏:​​true,

$ b $ err = db.DB(config.DatabaseName).C(users)。EnsureIndex(phoneIndex)
if err!= nil {
panic(err )
}

router:= mux.NewRouter()
router.HandleFunc(/ login,publicWithDB(login,db))。Methods(POST)

如果err:= http.ListenAndServe(:5000,router); err!= nil {
log.Fatal(err)
}
}

func publicWithDB(fn http.HandlerFunc,db * mgo.Session)http.HandlerFunc {
return func(w http.ResponseWriter,r * http.Request){
dbsession:= db.Copy()
defer dbsession.Close()
fn(w, r.WithContext(context.WithValue(r.Context(),contextKeyDatabase,dbsession)))
}
}

func login(w http.ResponseWriter,r * http。请求){
r.ParseForm()//解析请求体
device:= r.Form.Get(device)

var deviceid bson.ObjectId
if bson.IsObjectIdHex(device){
deviceid = bson.ObjectIdHex(device)
}

db:= r.Context()。Value(contextKeyDatabase)。( * mgo.Session)

var device models.Device
err:= db.DB(config.DatabaseName).C(devices)。FindId(deviceid).One(&设备)

w.WriteHeader(200)
w.Write([] byte(utils.ResponseToString(models.Response {Status :200,消息:asdasd,Data:device})))

}


$ b $我发布了这个,因为我找不到一个完整的实现。

解决方案

下面是一个例子,在Go中看到了我自己和其他人构建Web应用程序。此代码未经测试,纯粹是例如。它缺少导入并可能有错误。



编辑添加了一个中间件示例。

main.go

  package main 

func main(){
mongoDBDialInfo:= & mgo.DialInfo {
Addrs:[] string {config.DatabaseURL},
超时:60 * time.Second,
数据库:config.DatabaseName,
用户名:config .DatabaseUsername,
Password:config.DatabasePassword,
}
$ b db,err:= mgo.DialWithInfo(mongoDBDialInfo)

if err!= nil {
log.Fatal(Can not Dial Mongo:,err)
}

defer db.Close()
db.SetMode(mgo.Monotonic,true )

phoneIndex:= mgo.Index {
Key:[] string {pp},
Unique:true,
DropDups:true,
背景:true,
稀疏:​​真,
}

err = db.DB(config.DatabaseName).C(user s)。EnsureIndex(phoneIndex)
if err!= nil {
panic(err)
}

mgoAdapter:= mongo.NewAdapter(db,config。 DatabaseName)
deviceStore:= mongo.NewDeviceStore(mgoAdapter)
userStore:= mongo.NewUserStore(mgoAdapter)

loginController:= controllers.NewLoginController(deviceStore)

router:= mux.NewRouter()
router.HandleFunc(/ login,middleware.AuthorizeUser(userStore)(http.HandlerFunc(loginController.Login))。Methods(POST)

if err:= http.ListenAndServe(:5000,router); err!= nil {
log.Fatal(err)
}
}

controllers / login.go

 包控制器

类型LoginController结构{
store DeviceStore

$ b $ func NewLoginController(store stores.DeviceStore)* LoginController {
return& LoginController {
store:store,
}


func(c * LoginController)Login(w http.ResponseWriter,r * http.Request){
r.ParseForm()//解析请求体
device:= r.Form.Get(device)
data,err:= c.store.FindByDevice(device)

var respose models.Response
if err != nil {
w.WriteHeader(500)
response = models.Response {Status:500,Message:fmt.Sprintf(error:%s,err)}
} else if data == nil {
w.WriteHeader(404)
response = models.Response {Status:404,Message:device not found}
} else {
res ponse = models.Response {状态:200,消息:找到设备,数据:数据}
}

//将套标题写入200,如果它尚未设置
w.Write([] byte(utils.ResponseToString(response)))
}

stores / stores.go

 包裹商店

类型DeviceStore界面{
FindByDevice(设备字符串)(* models.Device,error)
}

类型UserStore接口{
FindByToken(标记字符串)(* models.User,error)
}

中间件/ auth.go

 包中间件

func AuthorizeUser(store stores.UserStore)func(h * http.Handler)http.Handler {
return func(h * http .Handler)http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter,r * http.Request){
//授权用户
的逻辑//也可以存储用户在请求上下文
})
}
}



mongo / mongo.go

  package mongo 

类型适配器struct {
session * mgo.Session
databaseName string
}

func NewAdapter(session * mgo.Session,dbName string)* Adapter {
return& Adapter {session:session,databaseName:dbName}
}

type deviceStore struct {
* Adapter
}

func NewDeviceStore(adapter * Adapter)stores.DeviceStore {
return& deviceStore {adapter}
}

const devices =devices

func(s * deviceStore)FindByDevice(d string)(* models.Device,err){
sess:= s.session.copy ()
推迟sess.close()

var deviceID bson.ObjectId
if bson.IsObjectIdHex(d){
deviceID = bson.ObjectIdHex(d)


var device models.Device
err:= db.DB(s.databaseName).C(devices).FindId(deviceID).One(&device)
if err mgo.ErrNotFound {
return nil,nil
}
return& device,err
}

type userStore struct {
* Adapter
}

const users =users

func NewUserStore(adapter * Adapter)stores.UserStore {
return& userStore {adapter}
}

func(s * userStore)GetUserByToken(token string)(* models.User,error){
sess:= s.session.copy()
defer sess.close ()

var user models.User
err:= db.DB(s.databaseName).C(users).Find(bson.M {token:token})。一个(&用户)
如果err == mgo.ErrNotFound {
return nil,nil
}

return& user,err
}


I have been using mgo for my API but I'm seeing many current connections in my MongoDB (while using less than 5 devices for testing). By executing db.serverStatus().connections in my Mongo server I get: { "current" : 641, "available" : 838219, "totalCreated" : 1136 }. Below I transcript my issue in mgo's Github (Issue #429):

Is my way of using mgo in a web server the correct way? If not, can you give me a full example?

This code is not functional, take it as almost pseudo code (because of the missing parts like the imports or where the configs come from and models), but it is exactly how I am using mgo.

I must clarify that I'm building an API which is used by several mobile devices and webapps.

main.go

func main() {
    mongoDBDialInfo := &mgo.DialInfo{
        Addrs:    []string{config.DatabaseURL},
        Timeout:  60 * time.Second,
        Database: config.DatabaseName,
        Username: config.DatabaseUsername,
        Password: config.DatabasePassword,
    }

    db, err := mgo.DialWithInfo(mongoDBDialInfo)

    if err != nil {
        log.Fatal("Cannot Dial Mongo: ", err)
    }

    defer db.Close() 
    db.SetMode(mgo.Monotonic, true)

    phoneIndex := mgo.Index{
        Key:        []string{"pp"},
        Unique:     true,
        DropDups:   true,
        Background: true,
        Sparse:     true,
    }

    err = db.DB(config.DatabaseName).C("users").EnsureIndex(phoneIndex)
    if err != nil {
        panic(err)
    }

    router := mux.NewRouter()
    router.HandleFunc("/login", publicWithDB(login, db)).Methods("POST")

    if err := http.ListenAndServe(":5000", router); err != nil {
        log.Fatal(err)
    }
}

func publicWithDB(fn http.HandlerFunc, db *mgo.Session) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        dbsession := db.Copy()
        defer dbsession.Close()
        fn(w, r.WithContext(context.WithValue(r.Context(), contextKeyDatabase, dbsession)))
    }
}

func login(w http.ResponseWriter, r *http.Request) {
    r.ParseForm() // Parses the request body
    device := r.Form.Get("device")

    var deviceid bson.ObjectId
    if bson.IsObjectIdHex(device) {
        deviceid = bson.ObjectIdHex(device)
    }

    db := r.Context().Value(contextKeyDatabase).(*mgo.Session)

    var device models.Device
    err := db.DB(config.DatabaseName).C("devices").FindId(deviceid).One(&device)

    w.WriteHeader(200)
    w.Write([]byte(utils.ResponseToString(models.Response{Status: 200, Message: "asdasd", Data: device})))

}

I'm posting this because I couldn't find a complete implementation.

解决方案

Here's an example of how I have seen myself and others structure web apps in Go. This code is untested and is purely for example. It's missing imports and potentially has errors.

EDIT Added a middleware example.

main.go

package main

func main() {
    mongoDBDialInfo := &mgo.DialInfo{
        Addrs:    []string{config.DatabaseURL},
        Timeout:  60 * time.Second,
        Database: config.DatabaseName,
        Username: config.DatabaseUsername,
        Password: config.DatabasePassword,
    }

    db, err := mgo.DialWithInfo(mongoDBDialInfo)

    if err != nil {
        log.Fatal("Cannot Dial Mongo: ", err)
    }

    defer db.Close() 
    db.SetMode(mgo.Monotonic, true)

    phoneIndex := mgo.Index{
        Key:        []string{"pp"},
        Unique:     true,
        DropDups:   true,
        Background: true,
        Sparse:     true,
    }

    err = db.DB(config.DatabaseName).C("users").EnsureIndex(phoneIndex)
    if err != nil {
        panic(err)
    }

    mgoAdapter := mongo.NewAdapter(db, config.DatabaseName)
    deviceStore := mongo.NewDeviceStore(mgoAdapter)
    userStore := mongo.NewUserStore(mgoAdapter)

    loginController := controllers.NewLoginController(deviceStore)

    router := mux.NewRouter()
    router.HandleFunc("/login", middleware.AuthorizeUser(userStore)(http.HandlerFunc(loginController.Login)).Methods("POST")

    if err := http.ListenAndServe(":5000", router); err != nil {
        log.Fatal(err)
    }
}

controllers/login.go

package controllers

type LoginController struct { 
    store DeviceStore
}

func NewLoginController(store stores.DeviceStore) *LoginController {
    return &LoginController{
        store: store,
    }
}

func (c *LoginController) Login(w http.ResponseWriter, r *http.Request) {
    r.ParseForm() // Parses the request body
    device := r.Form.Get("device")
    data, err := c.store.FindByDevice(device)

    var respose models.Response
    if err != nil {
        w.WriteHeader(500)
        response = models.Response{Status: 500, Message: fmt.Sprintf("error: %s", err)}
    } else if data == nil {
        w.WriteHeader(404)
        response = models.Response{Status: 404, Message: "device not found"}
    } else {
        response = models.Response{Status: 200, Message: "device found", Data: data}
    }

    // Write sets header to 200 if it hasn't been set already
    w.Write([]byte(utils.ResponseToString(response)))
}

stores/stores.go

package stores

type DeviceStore interface {
    FindByDevice(device string) (*models.Device, error)
}

type UserStore interface {
    FindByToken(token string) (*models.User, error)
}

middleware/auth.go

package middleware

func AuthorizeUser(store stores.UserStore) func(h *http.Handler) http.Handler {
    return func(h *http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // Logic for authorizing user
            // Could also store user in the request context
        })
    }
}

mongo/mongo.go

package mongo

type Adapter struct {
    session      *mgo.Session
    databaseName string
}

func NewAdapter(session *mgo.Session, dbName string) *Adapter {
    return &Adapter{session: session, databaseName: dbName}
}

type deviceStore struct {
    *Adapter
}

func NewDeviceStore(adapter *Adapter) stores.DeviceStore {
    return &deviceStore{adapter}
}

const devices = "devices"

func (s *deviceStore) FindByDevice(d string) (*models.Device, err) {
    sess := s.session.copy()
    defer sess.close()

    var deviceID bson.ObjectId
    if bson.IsObjectIdHex(d) {
        deviceID = bson.ObjectIdHex(d)
    }

    var device models.Device
    err := db.DB(s.databaseName).C(devices).FindId(deviceID).One(&device)
    if err == mgo.ErrNotFound {
        return nil, nil
    }
    return &device, err
}

type userStore struct {
    *Adapter
}

const users = "users"

func NewUserStore(adapter *Adapter) stores.UserStore {
    return &userStore{adapter}
}

func (s *userStore) GetUserByToken(token string) (*models.User, error) {
    sess := s.session.copy()
    defer sess.close()

    var user models.User
    err := db.DB(s.databaseName).C(users).Find(bson.M{"token": token}).One(&user)
    if err == mgo.ErrNotFound {
        return nil, nil
    }

    return &user, err
}

这篇关于与上下文一起使用mgo的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆