package mongo import ( "encoding/json" "strings" "github.com/vbatts/imgsrv/dbutil" "github.com/vbatts/imgsrv/types" "labix.org/v2/mgo" "labix.org/v2/mgo/bson" ) func init() { dbutil.Handles["mongo"] = &mongoHandle{} } const defaultDbName = "filesrv" type dbConfig struct { Seed string // mongo host seed to Dial into User string // mongo credentials, if needed Pass string // mongo credentials, if needed DbName string // mongo database name, if needed } type mongoHandle struct { config dbConfig Session *mgo.Session FileDb *mgo.Database Gfs *mgo.GridFS } func (h *mongoHandle) Init(config []byte, err error) error { if err != nil { return err } h.config = dbConfig{} if err := json.Unmarshal(config, &h.config); err != nil { return err } h.Session, err = mgo.Dial(h.config.Seed) if err != nil { return err } if len(h.config.DbName) > 0 { h.FileDb = h.Session.DB(h.config.DbName) } else { h.FileDb = h.Session.DB(defaultDbName) } if len(h.config.User) > 0 && len(h.config.Pass) > 0 { err = h.FileDb.Login(h.config.User, h.config.Pass) if err != nil { return err } } h.Gfs = h.FileDb.GridFS("fs") return nil } func (h mongoHandle) Close() error { h.Session.Close() return nil } // pass through for GridFs func (h mongoHandle) Open(filename string) (file dbutil.File, err error) { return h.Gfs.Open(strings.ToLower(filename)) } // pass through for GridFs func (h mongoHandle) Create(filename string) (file dbutil.File, err error) { return h.Gfs.Create(strings.ToLower(filename)) } // pass through for GridFs func (h mongoHandle) Remove(filename string) (err error) { return h.Gfs.Remove(strings.ToLower(filename)) } // Find files by their MD5 checksum func (h mongoHandle) FindFilesByMd5(md5 string) (files []types.File, err error) { err = h.Gfs.Find(bson.M{"md5": md5}).Sort("-metadata.timestamp").All(&files) return files, err } // match for file name // XXX this is not used func (h mongoHandle) FindFilesByName(filename string) (files []types.File, err error) { err = h.Gfs.Find(bson.M{"filename": filename}).Sort("-metadata.timestamp").All(&files) return files, err } // Case-insensitive pattern match for file name func (h mongoHandle) FindFilesByPatt(filenamePat string) (files []types.File, err error) { err = h.Gfs.Find(bson.M{"filename": bson.M{"$regex": filenamePat, "$options": "i"}}).Sort("-metadata.timestamp").All(&files) return files, err } // Case-insensitive pattern match for file name func (h mongoHandle) FindFilesByKeyword(keyword string) (files []types.File, err error) { err = h.Gfs.Find(bson.M{"metadata.keywords": strings.ToLower(keyword)}).Sort("-metadata.timestamp").All(&files) return files, err } // Get all the files. // Pass -1 for all files. func (h mongoHandle) GetFiles(limit int) (files []types.File, err error) { //files = []types.File{} if limit == -1 { err = h.Gfs.Find(nil).Sort("-metadata.timestamp").All(&files) } else { err = h.Gfs.Find(nil).Sort("-metadata.timestamp").Limit(limit).All(&files) } return files, err } // Count the filename matches func (h mongoHandle) CountFiles(filename string) (count int, err error) { query := h.Gfs.Find(bson.M{"filename": strings.ToLower(filename)}) return query.Count() } // Get one file back, by searching by file name func (h mongoHandle) GetFileByFilename(filename string) (thisFile types.File, err error) { err = h.Gfs.Find(bson.M{"filename": strings.ToLower(filename)}).One(&thisFile) if err != nil { return thisFile, err } return thisFile, nil } // Check whether this types.File filename is on Mongo func (h mongoHandle) HasFileByFilename(filename string) (exists bool, err error) { c, err := h.CountFiles(filename) if err != nil { return false, err } exists = (c > 0) return exists, nil } // XXX this is not used func (h mongoHandle) HasFileByMd5(md5 string) (exists bool, err error) { c, err := h.Gfs.Find(bson.M{"md5": md5}).Count() if err != nil { return false, err } exists = (c > 0) return exists, nil } // XXX this is not used func (h mongoHandle) HasFileByKeyword(keyword string) (exists bool, err error) { c, err := h.Gfs.Find(bson.M{"metadata": bson.M{"keywords": strings.ToLower(keyword)}}).Count() if err != nil { return false, err } exists = (c > 0) return exists, nil } // get a list of file extensions and their frequency count func (h mongoHandle) GetExtensions() (kp []types.IdCount, err error) { job := &mgo.MapReduce{ Map: ` function() { if (!this.filename) { return; } s = this.filename.split(".") ext = s[s.length - 1] // get the last segment of the split emit(ext,1); } `, Reduce: ` function(previous, current) { var count = 0; for (index in current) { count += current[index]; } return count; } `, } if _, err := h.Gfs.Find(nil).MapReduce(job, &kp); err != nil { return kp, err } // Less than effecient, but cleanest place to put this for i := range kp { kp[i].Root = "ext" // for extension. Maps to /ext/ } return kp, nil } // get a list of keywords and their frequency count func (h mongoHandle) GetKeywords() (kp []types.IdCount, err error) { job := &mgo.MapReduce{ Map: ` function() { if (!this.metadata.keywords) { return; } for (index in this.metadata.keywords) { emit(this.metadata.keywords[index], 1); } } `, Reduce: ` function(previous, current) { var count = 0; for (index in current) { count += current[index]; } return count; } `, } if _, err := h.Gfs.Find(nil).MapReduce(job, &kp); err != nil { return kp, err } // Less than effecient, but cleanest place to put this for i := range kp { kp[i].Root = "k" // for keyword. Maps to /k/ } return kp, nil }