title: save session in mongodb golang
body: <p>I m using golang in the back end and mongodb is my database.
  I wanted to store the user session(betwen login and logout )of my web application in the mongodb for the persistence.Since there is provider available only for mysql not for mongodb,I edited it to support mongodb.But when i try to use it i m getting the invalid memory  address or nil pointer dereference.
  The code is as follows and please if there is any better way to code please let me know.Thanks</p>
  
  <pre><code>type (
      SessionStore struct {
          c      *mgo.Session
          sid    string
          lock   sync.RWMutex
          values map[interface{}]interface{}
      }
  )
  
  var mgopder = &amp;Provider{}
  
  func (st *SessionStore) Set(key, value interface{}) error {
      st.lock.Lock()
      defer st.lock.Unlock()
      st.values[key] = value
      return nil
  }
  
  // Get value from mongodb session
  func (st *SessionStore) Get(key interface{}) interface{} {
      st.lock.RLock()
      defer st.lock.RUnlock()
      if v, ok := st.values[key]; ok {
          return v
      }
      return nil
  }
  
  // Delete value in mongodb session
  func (st *SessionStore) Delete(key interface{}) error {
      st.lock.Lock()
      defer st.lock.Unlock()
      delete(st.values, key)
      return nil
  }
  
  // Flush clear all values in mongodb session
  func (st *SessionStore) Flush() error {
      st.lock.Lock()
      defer st.lock.Unlock()
      st.values = make(map[interface{}]interface{})
      return nil
  }
  
  // SessionID get session id of this mongodb session store
  func (st *SessionStore) SessionID() string {
      return st.sid
  }
  
  // SessionRelease save mongodb session values to database.
  // must call this method to save values to database.
  func (st *SessionStore) SessionRelease(w http.ResponseWriter) {
      defer st.c.Close()
      b, err := session.EncodeGob(st.values)
      if err != nil {
          return
      }
      st.c.DB("Employee").C("Sessions").Update(nil, bson.M{"$set": bson.M{
          "session_data":   b,
          "session_expiry": time.Now().Unix(),
          "session_key":    st.sid,
      },
      },
      )
  
      /*st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?",
      b, time.Now().Unix(), st.sid)*/
  }
  
  type Provider struct {
      maxlifetime int64
      savePath    string
      Database    string
  }
  
  // connect to mongodb
  func (mp *Provider) connectInit() *mgo.Session {
      ds, err := mgo.Dial("Employee")
      if err != nil {
          return nil
      }
      return ds
  }
  
  // SessionInit init mongodb session.
  // savepath is the connection string of mongodb
  func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error {
      mp.maxlifetime = maxlifetime
      mp.savePath = savePath
      mp.Database = "Employee"
      return nil
  }
  
  // SessionRead get mysql session by sid
  func (mp *Provider) SessionRead(sid string) (session.Store, error) {
      var sessiondata []byte
      ds := mp.connectInit()
      defer ds.Close()
      c := ds.DB(mp.Database).C("Session")
      err := c.Find(bson.M{
          "session_key": sid,
      }).Select(bson.M{"session_data": 1}).All(&amp;sessiondata)
      if err != nil {
          if err.Error() == "not found" {
              c.Insert(bson.M{
                  "session_key":    sid,
                  "session_data":   " ",
                  "session_expiry": time.Now().Unix(),
              })
          }
      }
  
      var kv map[interface{}]interface{}
      if len(sessiondata) == 0 {
          kv = make(map[interface{}]interface{})
      } else {
          kv, err = session.DecodeGob(sessiondata)
          if err != nil {
              return nil, err
          }
      }
      rs := &amp;SessionStore{c: ds, sid: sid, values: kv}
      return rs, nil
  }
  
  // SessionExist check mongodb session exist
  func (mp *Provider) SessionExist(sid string) bool {
      var sessiondata []byte
      ds := mp.connectInit()
      defer ds.Close()
      c := ds.DB("Employee").C("Sessions")
      err := c.Find(bson.M{
          "session_key": sid,
      }).Select(bson.M{
          "session_data": 1,
      }).One(&amp;sessiondata)
      if err != nil {
          if err.Error() == "not found" {
              return false
          }
      }
      return true
  
  }
  
  // SessionRegenerate generate new sid for mysql session
  func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
      var sessiondata []byte
      ds := mp.connectInit()
      defer ds.Close()
      c := ds.DB("Employee").C("Sessions")
      err := c.Find(bson.M{
          "session_key": oldsid,
      }).Select(bson.M{
          "session_data": 1,
      }).One(&amp;sessiondata)
      if err != nil {
          if err.Error() == "not found" {
              c.Insert(bson.M{
                  "sessoin_key":    oldsid,
                  "session_data":   " ",
                  "session_expiry": time.Now().Unix(),
              })
          }
      }
      /*  row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
  
          err := row.Scan(&amp;sessiondata)
  
      c.Update(bson.M{"sessoin_key": oldsid}, bson.M{
          "$set": bson.M{
              "session_key": sid,
          },
      })
      /*c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid)
       */
      var kv map[interface{}]interface{}
      if len(sessiondata) == 0 {
          kv = make(map[interface{}]interface{})
      } else {
          kv, err = session.DecodeGob(sessiondata)
          if err != nil {
              return nil, err
          }
      }
      rs := &amp;SessionStore{c: ds, sid: sid, values: kv}
      return rs, nil
  }
  
  // SessionDestroy delete mysql session by sid
  func (mp *Provider) SessionDestroy(sid string) error {
      ds := mp.connectInit()
      defer ds.Close()
      c := ds.DB("Employee").C("Sessions")
      c.Remove(bson.M{
          "session_key": sid,
      }) 
      return nil
  }
  
  // SessionGC delete expired values in mysql session
  func (mp *Provider) SessionGC() {
      ds := mp.connectInit()
      defer ds.Close()
      c := ds.DB("Employee").C("Sessions")
      c.Remove(bson.M{
          "session_expiry": bson.M{
              "$lt": time.Now().Unix() - mp.maxlifetime,
          },
      })
  return
  }
  
  // SessionAll count values in mysql session
  func (mp *Provider) SessionAll() int {
      var total int
      ds := mp.connectInit()
      defer ds.Close()
      c := ds.DB("Employee").C("Sessions")
      total, err := c.Count()
  
      if err != nil {
          return 0
      }
      return total
  }
  
  func init() {
      session.Register("mongodb", mgopder)
  }
  </code></pre>
  
  <p>Error:</p>
  
  <pre><code>panic: runtime error: invalid memory address or nil pointer dereference
          panic: runtime error: invalid memory address or nil pointer dereference
  [signal 0xc0000005 code=0x1 addr=0x0 pc=0x6db254]
  
  goroutine 6 [running]:
  panic(0xa2f560, 0xc0820080b0)
          C:/Go/src/runtime/panic.go:481 +0x3f4
  gopkg.in/mgo%2ev2.(*Session).Close(0x0)
          C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:1612 +0x144
  panic(0xa2f560, 0xc0820080b0)
          C:/Go/src/runtime/panic.go:443 +0x4f7
  gopkg.in/mgo%2ev2.(*Session).acquireSocket(0x0, 0xc082290000, 0x0, 0x0, 0x0)
          C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4409 +0x4ba
  gopkg.in/mgo%2ev2.(*Collection).writeOp(0xc082279f30, 0x8feb80, 0xc082326060, 0xc082326001, 0x0, 0x0, 0x0)
          C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4604 +0xe7
  gopkg.in/mgo%2ev2.(*Collection).Remove(0xc082279f30, 0x9d4700, 0xc082326030, 0x0, 0x0)
          C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:2586 +0x15c
  sample/models.(*Provider).SessionGC(0xe2f5a0)
          C:/Projects/Go/src/sample/models/model.go:234 +0x3dc
  github.com/astaxie/beego/session.(*Manager).GC(0xc082258b20)
          C:/Projects/Go/src/github.com/astaxie/beego/session/session.go:271 +0x48
  created by github.com/astaxie/beego.registerSession
          C:/Projects/Go/src/github.com/astaxie/beego/hooks.go:68 +0x31d
  </code></pre>