qmgo
Qmgo - The Go driver for MongoDB. It‘s based on official mongo-go-driver but easier to use like Mgo.
Top Related Projects
The MongoDB driver for Go
The Official Golang driver for MongoDB
general purpose extensions to golang's database/sql
The fantastic ORM library for Golang, aims to be developer friendly
Quick Overview
Qmgo is a MongoDB driver for Go that provides a simple and efficient way to interact with MongoDB databases. It is designed to be a lightweight and easy-to-use alternative to the official MongoDB Go driver, with a focus on providing a more intuitive and developer-friendly API.
Pros
- Simple and Intuitive API: Qmgo offers a straightforward and easy-to-use API, making it accessible for developers who are new to MongoDB or Go.
- Performance Optimization: The library is designed to be efficient and performant, with features like automatic connection pooling and connection management.
- Compatibility with the Official MongoDB Go Driver: Qmgo is compatible with the official MongoDB Go driver, allowing developers to easily migrate existing projects.
- Extensive Documentation and Community Support: The project has comprehensive documentation and a growing community of contributors and users.
Cons
- Limited Functionality: Compared to the official MongoDB Go driver, Qmgo may have a more limited set of features and functionality.
- Potential Compatibility Issues: As a third-party library, Qmgo may not always be in sync with the latest updates and changes in the official MongoDB Go driver.
- Smaller Community: While the Qmgo community is growing, it may not have the same level of support and resources as the official MongoDB Go driver.
- Lack of Advanced Features: Qmgo may not provide the same level of advanced features and customization options as the official MongoDB Go driver.
Code Examples
Here are a few code examples demonstrating the usage of Qmgo:
Connecting to a MongoDB Database
import (
"context"
"fmt"
"github.com/qiniu/qmgo"
)
func main() {
ctx := context.Background()
client, err := qmgo.NewClient(ctx, &qmgo.Config{
Uri: "mongodb://localhost:27017",
Database: "test",
})
if err != nil {
fmt.Println("connect to mongodb error:", err)
return
}
defer client.Close(ctx)
// Use the client to interact with the MongoDB database
// ...
}
Inserting a Document
type Person struct {
Name string `bson:"name"`
Age int `bson:"age"`
}
func main() {
ctx := context.Background()
client, _ := qmgo.NewClient(ctx, &qmgo.Config{
Uri: "mongodb://localhost:27017",
Database: "test",
})
defer client.Close(ctx)
coll := client.Database("test").Collection("persons")
person := Person{
Name: "John Doe",
Age: 30,
}
_, err := coll.InsertOne(ctx, person)
if err != nil {
fmt.Println("insert error:", err)
return
}
}
Querying Documents
func main() {
ctx := context.Background()
client, _ := qmgo.NewClient(ctx, &qmgo.Config{
Uri: "mongodb://localhost:27017",
Database: "test",
})
defer client.Close(ctx)
coll := client.Database("test").Collection("persons")
filter := bson.M{"age": bson.M{"$gt": 25}}
var persons []Person
err := coll.Find(ctx, filter).All(&persons)
if err != nil {
fmt.Println("query error:", err)
return
}
for _, p := range persons {
fmt.Println(p)
}
}
Getting Started
To get started with Qmgo, follow these steps:
- Install the Qmgo package:
go get github.com/qiniu/qmgo
- Import the Qmgo package in your Go code:
import "github.com/qiniu/qmgo"
- Create a new Qmgo client and connect to a MongoDB database:
ctx := context.Background()
Competitor Comparisons
The MongoDB driver for Go
Pros of mgo
- More established and widely used in the Go community
- Extensive documentation and community support
- Supports a broader range of MongoDB versions
Cons of mgo
- No longer actively maintained (last commit in 2018)
- Lacks support for newer MongoDB features and optimizations
- May have compatibility issues with recent Go versions
Code Comparison
mgo:
session, err := mgo.Dial("mongodb://localhost")
if err != nil {
panic(err)
}
defer session.Close()
c := session.DB("test").C("users")
err = c.Insert(bson.M{"name": "John", "age": 30})
qmgo:
ctx := context.Background()
client, err := qmgo.NewClient(ctx, &qmgo.Config{Uri: "mongodb://localhost"})
if err != nil {
panic(err)
}
defer client.Close(ctx)
coll := client.Database("test").Collection("users")
_, err = coll.InsertOne(ctx, bson.M{"name": "John", "age": 30})
The main differences in the code are:
- qmgo uses a context-based API
- qmgo's client creation is more streamlined
- mgo uses
Insert
, while qmgo usesInsertOne
- qmgo's API is more aligned with the official MongoDB Go driver
Overall, qmgo offers a more modern and actively maintained alternative to mgo, with better support for recent MongoDB features and Go practices.
The Official Golang driver for MongoDB
Pros of mongo-go-driver
- Official MongoDB driver with comprehensive feature support
- Extensive documentation and community support
- More frequent updates and maintenance
Cons of mongo-go-driver
- Steeper learning curve for beginners
- More verbose API, requiring more code for common operations
Code Comparison
mongo-go-driver:
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017"))
collection := client.Database("testdb").Collection("users")
result, err := collection.InsertOne(context.TODO(), bson.D{{"name", "John"}, {"age", 30}})
qmgo:
cli, err := qmgo.NewClient(context.Background(), &qmgo.Config{Uri: "mongodb://localhost:27017"})
db := cli.Database("testdb")
coll := db.Collection("users")
_, err := coll.InsertOne(context.Background(), bson.M{"name": "John", "age": 30})
Summary
mongo-go-driver is the official MongoDB driver for Go, offering comprehensive features and extensive support. It's well-maintained but can be more complex for beginners. qmgo, on the other hand, provides a simpler API inspired by the MongoDB shell, making it easier to use for common operations. However, it may lack some advanced features and has a smaller community compared to the official driver.
general purpose extensions to golang's database/sql
Pros of sqlx
- Supports multiple database types (MySQL, PostgreSQL, SQLite)
- Provides a more SQL-centric approach, allowing direct use of SQL queries
- Offers a lightweight and flexible API for database operations
Cons of sqlx
- Lacks built-in ODM (Object-Document Mapping) features
- Requires more manual handling of database operations compared to Qmgo
- May require more boilerplate code for complex queries and operations
Code Comparison
sqlx:
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
rows, err := db.Queryx("SELECT * FROM users WHERE id = $1", id)
var user User
err = rows.StructScan(&user)
Qmgo:
cli, err := qmgo.NewClient(context.Background(), &qmgo.Config{Uri: "mongodb://localhost:27017"})
db := cli.Database("example")
coll := db.Collection("user")
err = coll.Find(context.Background(), bson.M{"name": "user1"}).One(&user)
Summary
sqlx is a versatile SQL library supporting multiple databases, offering a SQL-centric approach with a lightweight API. It provides more flexibility but requires more manual handling of database operations. Qmgo, on the other hand, is specifically designed for MongoDB, offering built-in ODM features and a more streamlined API for document-based operations. The choice between the two depends on the specific database requirements and development preferences of the project.
The fantastic ORM library for Golang, aims to be developer friendly
Pros of gorm
- More mature and widely adopted ORM for Go, with a larger community and ecosystem
- Supports multiple databases (MySQL, PostgreSQL, SQLite, etc.) out of the box
- Offers advanced features like associations, hooks, and migrations
Cons of gorm
- Steeper learning curve due to its extensive feature set
- Can be slower for simple queries compared to raw SQL or lighter ORMs
- May introduce overhead for applications with simple database needs
Code Comparison
qmgo:
cli, err := qmgo.NewClient(ctx, &qmgo.Config{Uri: "mongodb://localhost:27017"})
db := cli.Database("test")
coll := db.Collection("user")
err := coll.InsertOne(ctx, User{Name: "Alice", Age: 30})
gorm:
db, err := gorm.Open(mysql.Open("user:password@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"), &gorm.Config{})
user := User{Name: "Alice", Age: 30}
result := db.Create(&user)
Summary
qmgo is a MongoDB-specific driver for Go, offering a simpler API for MongoDB operations. gorm, on the other hand, is a full-featured ORM supporting multiple databases. While gorm provides more flexibility and features, qmgo may be more suitable for projects exclusively using MongoDB and requiring a lightweight solution.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Qmgo
English | ç®ä½ä¸æ
Qmgo
is a Go
driver
for MongoDB
. It is based on MongoDB official driver, but easier to use like mgo (such as the chain call).
-
Qmgo
allows users to use the new features ofMongoDB
in a more elegant way. -
Qmgo
is the first choice for migrating frommgo
to the newMongoDB driver
with minimal code changes.
Requirements
-Go 1.10
and above.
-MongoDB 2.6
and above.
Features
- CRUD to documents, with all official supported options
- Sortãlimitãcountãselectãdistinct
- Transactions
- Hooks
- Automatically default and custom fields
- Predefine operator keys
- Aggregateãindexes operationãcursor
- Validation tags
- Plugin
Installation
- Use
go mod
to automatically install dependencies byimport github.com/qiniu/qmgo
Or
- Use
go get github.com/qiniu/qmgo
Usage
-
Start
import
and create a new connectionimport ( "context" "github.com/qiniu/qmgo" ) ctx := context.Background() client, err := qmgo.NewClient(ctx, &qmgo.Config{Uri: "mongodb://localhost:27017"}) db := client.Database("class") coll := db.Collection("user")
If your connection points to a fixed database and collection, recommend using the following way to initialize the connection. All operations can be based on
cli
:cli, err := qmgo.Open(ctx, &qmgo.Config{Uri: "mongodb://localhost:27017", Database: "class", Coll: "user"})
The following examples will be based on
cli
, if you use the first way for initialization, replacecli
withclient
ãdb
orcoll
Make sure to defer a call to Disconnect after instantiating your client:
defer func() { if err = cli.Close(ctx); err != nil { panic(err) } }()
-
Create index
Before doing the operation, we first initialize some data:
type UserInfo struct { Name string `bson:"name"` Age uint16 `bson:"age"` Weight uint32 `bson:"weight"` } var userInfo = UserInfo{ Name: "xm", Age: 7, Weight: 40, }
Create index
cli.CreateOneIndex(context.Background(), options.IndexModel{Key: []string{"name"}}) cli.CreateIndexes(context.Background(), []options.IndexModel{{Key: []string{"id2", "id3"}}})
-
Insert a document
// insert one document result, err := cli.InsertOne(ctx, userInfo)
-
Find a document
// find one document one := UserInfo{} err = cli.Find(ctx, bson.M{"name": userInfo.Name}).One(&one)
-
Delete documents
err = cli.Remove(ctx, bson.M{"age": 7})
-
Insert multiple data
// multiple insert var userInfos = []UserInfo{ UserInfo{Name: "a1", Age: 6, Weight: 20}, UserInfo{Name: "b2", Age: 6, Weight: 25}, UserInfo{Name: "c3", Age: 6, Weight: 30}, UserInfo{Name: "d4", Age: 6, Weight: 35}, UserInfo{Name: "a1", Age: 7, Weight: 40}, UserInfo{Name: "a1", Age: 8, Weight: 45}, } result, err = cli.Collection.InsertMany(ctx, userInfos)
-
Search all, sort and limit
// find all, sort and limit batch := []UserInfo{} cli.Find(ctx, bson.M{"age": 6}).Sort("weight").Limit(7).All(&batch)
-
Count
count, err := cli.Find(ctx, bson.M{"age": 6}).Count()
-
Update
// UpdateOne one err := cli.UpdateOne(ctx, bson.M{"name": "d4"}, bson.M{"$set": bson.M{"age": 7}}) // UpdateAll result, err := cli.UpdateAll(ctx, bson.M{"age": 6}, bson.M{"$set": bson.M{"age": 10}})
-
Select
err := cli.Find(ctx, bson.M{"age": 10}).Select(bson.M{"age": 1}).One(&one)
-
Aggregate
matchStage := bson.D{{"$match", []bson.E{{"weight", bson.D{{"$gt", 30}}}}}} groupStage := bson.D{{"$group", bson.D{{"_id", "$name"}, {"total", bson.D{{"$sum", "$age"}}}}}} var showsWithInfo []bson.M err = cli.Aggregate(context.Background(), Pipeline{matchStage, groupStage}).All(&showsWithInfo)
-
Support All mongoDB Options when create connection
poolMonitor := &event.PoolMonitor{ Event: func(evt *event.PoolEvent) { switch evt.Type { case event.GetSucceeded: fmt.Println("GetSucceeded") case event.ConnectionReturned: fmt.Println("ConnectionReturned") } }, } opt := options.Client().SetPoolMonitor(poolMonitor) // more options use the chain options. cli, err := Open(ctx, &Config{Uri: URI, Database: DATABASE, Coll: COLL}, opt)
-
Transactions
The super simple and powerful transaction, with features like
timeout
ãretry
:callback := func(sessCtx context.Context) (interface{}, error) { // Important: make sure the sessCtx used in every operation in the whole transaction if _, err := cli.InsertOne(sessCtx, bson.D{{"abc", int32(1)}}); err != nil { return nil, err } if _, err := cli.InsertOne(sessCtx, bson.D{{"xyz", int32(999)}}); err != nil { return nil, err } return nil, nil } result, err = cli.DoTransaction(ctx, callback)
-
Predefine operator keys
// aggregate matchStage := bson.D{{operator.Match, []bson.E{{"weight", bson.D{{operator.Gt, 30}}}}}} groupStage := bson.D{{operator.Group, bson.D{{"_id", "$name"}, {"total", bson.D{{operator.Sum, "$age"}}}}}} var showsWithInfo []bson.M err = cli.Aggregate(context.Background(), Pipeline{matchStage, groupStage}).All(&showsWithInfo)
-
Hooks
Qmgo flexible hooks:
type User struct { Name string `bson:"name"` Age int `bson:"age"` } func (u *User) BeforeInsert(ctx context.Context) error { fmt.Println("before insert called") return nil } func (u *User) AfterInsert(ctx context.Context) error { fmt.Println("after insert called") return nil } u := &User{Name: "Alice", Age: 7} _, err := cli.InsertOne(context.Background(), u)
-
Automatically fields
Qmgo support two ways to make specific fields automatically update in specific API
- Default fields
Inject
field.DefaultField
in document struct, Qmgo will updatecreateAt
ãupdateAt
and_id
in update and insert operation.type User struct { field.DefaultField `bson:",inline"` Name string `bson:"name"` Age int `bson:"age"` } u := &User{Name: "Lucas", Age: 7} _, err := cli.InsertOne(context.Background(), u) // Fields with tag createAtãupdateAt and _id will be generated automatically
- Custom fields
Define the custom fields, Qmgo will update them in update and insert operation.
type User struct { Name string `bson:"name"` Age int `bson:"age"` MyId string `bson:"myId"` CreateTimeAt time.Time `bson:"createTimeAt"` UpdateTimeAt int64 `bson:"updateTimeAt"` } // Define the custom fields func (u *User) CustomFields() field.CustomFieldsBuilder { return field.NewCustom().SetCreateAt("CreateTimeAt").SetUpdateAt("UpdateTimeAt").SetId("MyId") } u := &User{Name: "Lucas", Age: 7} _, err := cli.InsertOne(context.Background(), u) // CreateTimeAtãUpdateTimeAt and MyId will be generated automatically // suppose Id and ui is ready err = cli.ReplaceOne(context.Background(), bson.M{"_id": Id}, &ui) // UpdateTimeAt will update
Check examples here
-
Validation tags
Qmgo Validation tags is Based on go-playground/validator.
So Qmgo support all validations on structs in go-playground/validator, such as:
type User struct { FirstName string `bson:"fname"` LastName string `bson:"lname"` Age uint8 `bson:"age" validate:"gte=0,lte=130" ` // Age must in [0,130] Email string `bson:"e-mail" validate:"required,email"` // Email can't be empty string, and must has email format CreateAt time.Time `bson:"createAt" validate:"lte"` // CreateAt must lte than current time Relations map[string]string `bson:"relations" validate:"max=2"` // Relations can't has more than 2 elements }
Qmgo tags only supported in following APIï¼
InsertOneãInsertyManyãUpsertãUpsertIdãReplaceOne
-
Plugin
- Implement following method:
func Do(ctx context.Context, doc interface{}, opType operator.OpType, opts ...interface{}) error{ // do anything }
-
Call Register() in package middleware, register the method
Do
Qmgo will call
Do
before and after the operation
middleware.Register(Do)
The
hook
ãautomatically fields
andvalidation tags
in Qmgo run on plugin.
Qmgo
vs go.mongodb.org/mongo-driver
Below 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
.
How do we do ingo.mongodb.org/mongo-driver
:
// go.mongodb.org/mongo-driver
// find all, sort and limit
findOptions := options.Find()
findOptions.SetLimit(7) // set limit
var sorts D
sorts = append(sorts, E{Key: "weight", Value: 1})
findOptions.SetSort(sorts) // set sort
batch := []UserInfo{}
cur, err := coll.Find(ctx, bson.M{"age": 6}, findOptions)
cur.All(ctx, &batch)
How do we do in Qmgo
and mgo
:
// qmgo
// find all, sort and limit
batch := []UserInfo{}
cli.Find(ctx, bson.M{"age": 6}).Sort("weight").Limit(7).All(&batch)
// mgo
// find all, sort and limit
coll.Find(bson.M{"age": 6}).Sort("weight").Limit(7).All(&batch)
Qmgo
vs mgo
Differences between qmgo and mgo
Contributing
The Qmgo project welcomes all contributors. We appreciate your help!
Communication:
- Join qmgo discussions
Top Related Projects
The MongoDB driver for Go
The Official Golang driver for MongoDB
general purpose extensions to golang's database/sql
The fantastic ORM library for Golang, aims to be developer friendly
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot