{"id":13412381,"url":"https://github.com/qiniu/qmgo","last_synced_at":"2025-05-14T02:07:09.415Z","repository":{"id":40456377,"uuid":"284930248","full_name":"qiniu/qmgo","owner":"qiniu","description":"Qmgo - The Go driver for MongoDB. It‘s based on official mongo-go-driver but easier to use like Mgo.","archived":false,"fork":false,"pushed_at":"2024-10-31T09:14:38.000Z","size":490,"stargazers_count":1321,"open_issues_count":51,"forks_count":152,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-04-10T16:49:09.953Z","etag":null,"topics":["database","driver","go","mgo","mongo-go-driver","mongodb","mongodb-database","mongodb-driver"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qiniu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-04T09:06:00.000Z","updated_at":"2025-04-04T04:30:23.000Z","dependencies_parsed_at":"2024-11-27T16:00:32.138Z","dependency_job_id":"2df59948-f255-465f-a4e7-648eab8d0678","html_url":"https://github.com/qiniu/qmgo","commit_stats":{"total_commits":360,"total_committers":31,"mean_commits":"11.612903225806452","dds":0.5638888888888889,"last_synced_commit":"5d875cc05ef7abe35c7baa569c75caac7b2e50ad"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qiniu%2Fqmgo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qiniu%2Fqmgo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qiniu%2Fqmgo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qiniu%2Fqmgo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qiniu","download_url":"https://codeload.github.com/qiniu/qmgo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254052758,"owners_count":22006716,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","driver","go","mgo","mongo-go-driver","mongodb","mongodb-database","mongodb-driver"],"created_at":"2024-07-30T20:01:24.061Z","updated_at":"2025-05-14T02:07:04.402Z","avatar_url":"https://github.com/qiniu.png","language":"Go","funding_links":[],"categories":["Database Drivers","开源类库","Go","NoSQL Databases","数据库驱动程序","Generators","数据库驱动`连接和操作数据库工具`","Data Integration Frameworks","Repositories","数据库驱动"],"sub_categories":["NoSQL Database Drivers","数据库","Advanced Console UIs","NoSQL数据库驱动程序","SQL 查询语句构建库"],"readme":"# Qmgo \n\n[![Build Status](https://travis-ci.org/qiniu/qmgo.png?branch=master)](https://travis-ci.org/qiniu/qmgo)\n[![Coverage Status](https://codecov.io/gh/qiniu/qmgo/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/qmgo)\n[![Go Report Card](https://goreportcard.com/badge/github.com/qiniu/qmgo)](https://goreportcard.com/report/github.com/qiniu/qmgo)\n[![GitHub release](https://img.shields.io/github/v/tag/qiniu/qmgo.svg?label=release)](https://github.com/qiniu/qmgo/releases)\n[![GoDoc](https://pkg.go.dev/badge/github.com/qiniu/qmgo?status.svg)](https://pkg.go.dev/github.com/qiniu/qmgo?tab=doc) \n\nEnglish | [简体中文](README_ZH.md)\n\n`Qmgo` is a `Go` `driver` for `MongoDB` . It is based on [MongoDB official driver](https://github.com/mongodb/mongo-go-driver), but easier to use like [mgo](https://github.com/go-mgo/mgo) (such as the chain call). \n\n- `Qmgo` allows users to use the new features of `MongoDB` in a more elegant way.\n\n- `Qmgo` is the first choice for migrating from `mgo` to the new `MongoDB driver` with minimal code changes.\n\n## Requirements\n\n-`Go 1.10` and above.\n\n-`MongoDB 2.6` and above.\n\n## Features\n- CRUD to documents, with all official supported options\n- Sort、limit、count、select、distinct\n- Transactions\n- Hooks\n- Automatically default and custom fields\n- Predefine operator keys\n- Aggregate、indexes operation、cursor\n- Validation tags\n- Plugin\n\n## Installation\n\n- Use `go mod` to automatically install dependencies by `import github.com/qiniu/qmgo`\n\nOr \n\n- Use `go get github.com/qiniu/qmgo`\n\n## Usage\n\n- Start\n\n    `import` and create a new connection\n    ```go\n    import (\n        \"context\"\n      \n        \"github.com/qiniu/qmgo\"\n    )\n    \n    ctx := context.Background()\n    client, err := qmgo.NewClient(ctx, \u0026qmgo.Config{Uri: \"mongodb://localhost:27017\"})\n    db := client.Database(\"class\")\n    coll := db.Collection(\"user\")\n    ```\n    If your connection points to a fixed database and collection, recommend using the following way to initialize the connection.\n    All operations can be based on `cli`:\n    \n    ```go\n    cli, err := qmgo.Open(ctx, \u0026qmgo.Config{Uri: \"mongodb://localhost:27017\", Database: \"class\", Coll: \"user\"})\n    ```\n    \n    ***The following examples will be based on `cli`, if you use the first way for initialization, replace `cli` with `client`、`db` or `coll`***\n    \n    Make sure to defer a call to Disconnect after instantiating your client:\n    \n    ```go\n    defer func() {\n    if err = cli.Close(ctx); err != nil {\n            panic(err)\n        }\n    }()\n    ```\n\n- Create index\n\n    Before doing the operation, we first initialize some data:\n    \n    ```go\n    type UserInfo struct {\n        Name   string `bson:\"name\"`\n        Age    uint16 `bson:\"age\"`\n        Weight uint32 `bson:\"weight\"`\n    }\n    \n    var userInfo = UserInfo{\n        Name: \"xm\",\n        Age: 7,\n        Weight: 40,\n    }\n    ```\n    \n    Create index\n    \n    ```go\n    cli.CreateOneIndex(context.Background(), options.IndexModel{Key: []string{\"name\"}})\n    cli.CreateIndexes(context.Background(), []options.IndexModel{{Key: []string{\"id2\", \"id3\"}}})\n    ```\n\n- Insert a document\n\n    ```go\n    // insert one document\n    result, err := cli.InsertOne(ctx, userInfo)\n    ```\n\n- Find a document\n\n    ```go\n    // find one document\n      one := UserInfo{}\n      err = cli.Find(ctx, bson.M{\"name\": userInfo.Name}).One(\u0026one)\n    ```\n\n- Delete documents\n    \n    ```go\n    err = cli.Remove(ctx, bson.M{\"age\": 7})\n    ```\n\n- Insert multiple data\n\n    ```go\n    // multiple insert\n    var userInfos = []UserInfo{\n        UserInfo{Name: \"a1\", Age: 6, Weight: 20},\n        UserInfo{Name: \"b2\", Age: 6, Weight: 25},\n        UserInfo{Name: \"c3\", Age: 6, Weight: 30},\n        UserInfo{Name: \"d4\", Age: 6, Weight: 35},\n        UserInfo{Name: \"a1\", Age: 7, Weight: 40},\n        UserInfo{Name: \"a1\", Age: 8, Weight: 45},\n    }\n    result, err = cli.Collection.InsertMany(ctx, userInfos)\n    ```\n\n- Search all, sort and limit\n    ```go\n    // find all, sort and limit\n    batch := []UserInfo{}\n    cli.Find(ctx, bson.M{\"age\": 6}).Sort(\"weight\").Limit(7).All(\u0026batch)\n    ```\n- Count\n\n    ````go\n    count, err := cli.Find(ctx, bson.M{\"age\": 6}).Count()\n    ````\n\n- Update\n\n    ````go\n    // UpdateOne one\n    err := cli.UpdateOne(ctx, bson.M{\"name\": \"d4\"}, bson.M{\"$set\": bson.M{\"age\": 7}})\n    \n    // UpdateAll\n    result, err := cli.UpdateAll(ctx, bson.M{\"age\": 6}, bson.M{\"$set\": bson.M{\"age\": 10}})\n    ````\n\n- Select\n\n    ````go\n    err := cli.Find(ctx, bson.M{\"age\": 10}).Select(bson.M{\"age\": 1}).One(\u0026one)\n    ````\n\n- Aggregate\n\n    ```go\n    matchStage := bson.D{{\"$match\", []bson.E{{\"weight\", bson.D{{\"$gt\", 30}}}}}}\n    groupStage := bson.D{{\"$group\", bson.D{{\"_id\", \"$name\"}, {\"total\", bson.D{{\"$sum\", \"$age\"}}}}}}\n    var showsWithInfo []bson.M\n    err = cli.Aggregate(context.Background(), Pipeline{matchStage, groupStage}).All(\u0026showsWithInfo)\n    ```\n\n- Support All mongoDB Options when create connection\n\n    ````go\n    poolMonitor := \u0026event.PoolMonitor{\n        Event: func(evt *event.PoolEvent) {\n            switch evt.Type {\n            case event.GetSucceeded:\n                fmt.Println(\"GetSucceeded\")\n            case event.ConnectionReturned:\n                fmt.Println(\"ConnectionReturned\")\n            }\n        },\n    }\n    opt := options.Client().SetPoolMonitor(poolMonitor)  // more options use the chain options.\n    cli, err := Open(ctx, \u0026Config{Uri: URI, Database: DATABASE, Coll: COLL}, opt) \n    \n    \n    ````\n\n- Transactions\n\n    The super simple and powerful transaction, with features like `timeout`、`retry`:\n    ````go\n    callback := func(sessCtx context.Context) (interface{}, error) {\n        // Important: make sure the sessCtx used in every operation in the whole transaction\n        if _, err := cli.InsertOne(sessCtx, bson.D{{\"abc\", int32(1)}}); err != nil {\n            return nil, err\n        }\n        if _, err := cli.InsertOne(sessCtx, bson.D{{\"xyz\", int32(999)}}); err != nil {\n            return nil, err\n        }\n        return nil, nil\n    }\n    result, err = cli.DoTransaction(ctx, callback)\n    ````\n    [More about transaction](https://github.com/qiniu/qmgo/wiki/Transactions)\n\n- Predefine operator keys\n\n    ````go\n    // aggregate\n    matchStage := bson.D{{operator.Match, []bson.E{{\"weight\", bson.D{{operator.Gt, 30}}}}}}\n    groupStage := bson.D{{operator.Group, bson.D{{\"_id\", \"$name\"}, {\"total\", bson.D{{operator.Sum, \"$age\"}}}}}}\n    var showsWithInfo []bson.M\n    err = cli.Aggregate(context.Background(), Pipeline{matchStage, groupStage}).All(\u0026showsWithInfo)\n    ````\n\n- Hooks\n\n    Qmgo flexible hooks:\n\n    ````go\n    type User struct {\n        Name         string    `bson:\"name\"`\n        Age          int       `bson:\"age\"`\n    }\n    func (u *User) BeforeInsert(ctx context.Context) error {\n        fmt.Println(\"before insert called\")\n        return nil\n    }\n    func (u *User) AfterInsert(ctx context.Context) error {\n        fmt.Println(\"after insert called\")\n        return nil\n    }\n    \n    u := \u0026User{Name: \"Alice\", Age: 7}\n    _, err := cli.InsertOne(context.Background(), u)\n    ````\n    [More about hooks](https://github.com/qiniu/qmgo/wiki/Hooks)\n\n- Automatically fields\n\n    Qmgo support two ways to make specific fields automatically update in specific API\n   \n    - Default fields\n    \n    Inject `field.DefaultField` in document struct, Qmgo will update `createAt`、`updateAt` and `_id` in update and insert operation.\n    \n    ````go\n    type User struct {\n      field.DefaultField `bson:\",inline\"`\n    \n      Name string `bson:\"name\"`\n      Age  int    `bson:\"age\"`\n    }\n  \n  \tu := \u0026User{Name: \"Lucas\", Age: 7}\n  \t_, err := cli.InsertOne(context.Background(), u)\n    // Fields with tag createAt、updateAt and _id will be generated automatically \n    ```` \n\n    - Custom fields\n    \n    Define the custom fields, Qmgo will update them in update and insert operation.\n\n    ```go\n    type User struct {\n        Name string `bson:\"name\"`\n        Age  int    `bson:\"age\"`\n    \n        MyId         string    `bson:\"myId\"`\n        CreateTimeAt time.Time `bson:\"createTimeAt\"`\n        UpdateTimeAt int64     `bson:\"updateTimeAt\"`\n    }\n    // Define the custom fields\n    func (u *User) CustomFields() field.CustomFieldsBuilder {\n        return field.NewCustom().SetCreateAt(\"CreateTimeAt\").SetUpdateAt(\"UpdateTimeAt\").SetId(\"MyId\")\n    }\n  \n    u := \u0026User{Name: \"Lucas\", Age: 7}\n    _, err := cli.InsertOne(context.Background(), u)\n    // CreateTimeAt、UpdateTimeAt and MyId will be generated automatically \n  \n    // suppose Id and ui is ready\n  \terr = cli.ReplaceOne(context.Background(), bson.M{\"_id\": Id}, \u0026ui)\n    // UpdateTimeAt will update\n    ```\n\n    Check [examples here](https://github.com/qiniu/qmgo/blob/master/field_test.go)\n\n    [More about automatically fields](https://github.com/qiniu/qmgo/wiki/Automatically-update-fields)\n\n- Validation tags\n\n    Qmgo Validation tags is Based on [go-playground/validator](https://github.com/go-playground/validator).\n    \n    So Qmgo support [all validations on structs in go-playground/validator](https://github.com/go-playground/validator#usage-and-documentation), such as:\n    \n    ```go\n    type User struct {\n        FirstName string            `bson:\"fname\"`\n        LastName  string            `bson:\"lname\"`\n        Age       uint8             `bson:\"age\" validate:\"gte=0,lte=130\" `    // Age must in [0,130]\n        Email     string            `bson:\"e-mail\" validate:\"required,email\"` //  Email can't be empty string, and must has email format\n        CreateAt  time.Time         `bson:\"createAt\" validate:\"lte\"`          // CreateAt must lte than current time\n        Relations map[string]string `bson:\"relations\" validate:\"max=2\"`       // Relations can't has more than 2 elements\n    }\n    ```\n    \n    Qmgo tags only supported in following API：\n    ` InsertOne、InsertyMany、Upsert、UpsertId、ReplaceOne `\n\n- Plugin\n    \n    - Implement following method:\n    \n    ```go\n    func Do(ctx context.Context, doc interface{}, opType operator.OpType, opts ...interface{}) error{\n      // do anything\n    }\n    ```\n    \n    - Call Register() in package middleware, register the method `Do`\n    \n      Qmgo will call `Do` before and after the [operation](operator/operate_type.go)\n      \n    ```go\n    middleware.Register(Do)\n    ```\n    [Example](middleware/middleware_test.go)\n    \n    The `hook`、`automatically fields` and `validation tags` in Qmgo run on **plugin**.\n    \n## `Qmgo` vs `go.mongodb.org/mongo-driver`\n\nBelow we give an example of multi-file search、sort and limit to illustrate the similarities between `qmgo` and `mgo` and the improvement compare to `go.mongodb.org/mongo-driver`.\nHow do we do in`go.mongodb.org/mongo-driver`:\n\n```go\n// go.mongodb.org/mongo-driver\n// find all, sort and limit\nfindOptions := options.Find()\nfindOptions.SetLimit(7) // set limit\nvar sorts D\nsorts = append(sorts, E{Key: \"weight\", Value: 1})\nfindOptions.SetSort(sorts) // set sort\n\nbatch := []UserInfo{}\ncur, err := coll.Find(ctx, bson.M{\"age\": 6}, findOptions)\ncur.All(ctx, \u0026batch)\n```\n\nHow do we do in `Qmgo` and `mgo`:\n\n```go\n// qmgo\n// find all, sort and limit\nbatch := []UserInfo{}\ncli.Find(ctx, bson.M{\"age\": 6}).Sort(\"weight\").Limit(7).All(\u0026batch)\n\n// mgo\n// find all, sort and limit\ncoll.Find(bson.M{\"age\": 6}).Sort(\"weight\").Limit(7).All(\u0026batch)\n```\n\n## `Qmgo` vs `mgo`\n[Differences between qmgo and mgo](https://github.com/qiniu/qmgo/wiki/Differences-between-Qmgo-and-Mgo)\n \n## Contributing\n\nThe Qmgo project welcomes all contributors. We appreciate your help! \n\n## Communication:\n\n- Join [qmgo discussions](https://github.com/qiniu/qmgo/discussions)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqiniu%2Fqmgo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqiniu%2Fqmgo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqiniu%2Fqmgo/lists"}