When I worked with Mongo Go Driver, it was complicate to make a search, or update query document(s) with dynamic conditions.
For example, collection cars
that contains the following documents:
{ _id: 1, name: "abc1", status: "A", qty: 50, category: "sport", createdAt: ISODate("2019-11-02T17:04:11.102Z") }
{ _id: 2, name: "xyz1", status: "A", qty: 100, category: "sedan", createdAt: ISODate("2019-10-01T17:04:11.102Z") }
{ _id: 3, name: "xyz2", status: "D", qty: 25, category: "sport", createdAt: ISODate("2018-10-12T17:04:11.102Z") }
Our model:
...
type Car struct {
ID int `bson:"_id"`
Name string `bson:"name"`
Status string `bson:"status"`
Qty string `bson:"qty"`
Category string `bson:"category"`
CreatedAt time.Time `bson:"createdAt"`
}
Then what are you gonna do if you want to find all the cars with a name/status/category, or even all of them? It may look like this:
...
func (cm *CarManager) FindCars(ctx context.Context, in Car) (cars []*Car, err error) {
cars = []*Car{}
filter := bson.M{}
// filter by name
if in.Name != "" {
filter["name"] = in.Name
}
// filter by status
if in.Status != "" {
filter["status"] = in.Status
}
// filter by category
if in.Categroy != "" {
filter["category"] = in.Categroy
}
cur, err := cm.collection.Find(ctx, filter)
if err != nil {
return nil, err
}
// decode the result here
...
return
}
It’s boring, right? Then I wrote a simple util which called Gmob to resolve this. Let’s take a look:
...
import (
...
github.com/tungquach/gmob
...
)
...
func (cm *CarManager) FindCars(ctx context.Context, in Car) (cars []*Car, err error) {
cars = []*Car{}
// Examples
// in = Car{Name: "abc1"} => filter = bson.M{"name": "abc1"}
// in = Car{Name: "acb1", Status: "A", Category: "sport"} => filter = bson.M{"name": "abc1", "status": "A", "category": "sport"}
filter, _ := gmob.Build(in)
cur, err := cm.collection.Find(ctx, filter)
if err != nil {
return nil, err
}
// decode the result here
...
return
}
Now it looks more simple! And we can do the same for the update query:
...
import (
...
github.com/tungquach/gmob
...
)
...
func (cm *CarManager) UpdateCar(ctx context.Context, in Car) (err error) {
// Examples
// in = Car{ID: 1, Name: "abc1"} => filter = bson.M{"_id": 1, "name": "abc1"}
// in = Car{ID: 1, Name: "acb1", Status: "A", Category: "sport"} => filter = bson.M{"_id": 1, "name": "abc1", "status": "A", "category": "sport"}
setValues, _ := gmob.Build(in)
_, err = cm.collection.UpdateOne(ctx, bson.M{"_id": in.ID}, bson.M{"$set": setValues})
return
}
Conclusions
I hope Gmob can help us stay away from boring code :) If you have any thoughts, please don’t hesitate to give me feedback. Thank you so much!