
Golang MongoDb raw pagination
I’m writing a complex query (for a beginner user) for mongodb using the golang official driver, i’d like share my code to help other user.
I’ll use an aggragate to do the complex query, we need to step the first one to count the records of the query, the second step to get the elements at the request page.
var basePipeline = mongo.Pipeline{
{{“$lookup”, bson.D{
{“from”, “makers”},
{“localField”, “maker”},
{“foreignField”, “username”},
{“as”, “makerinfo”},
}}}}
The first piece fo the pipeline is the lookup, a similar left-join, we want join from the collection of products the makers. With the subpipeline we specify the conditions of the query:
var countPipeline mongo.Pipeline
var productsPipeline mongo.Pipelinesubpipeline := bson.D{
{“$match”, bson.D{{“$and”,
bson.A{
bson.D{{“name”, bson.M{“$regex”: “.*” + initial + “.*”, “$options”: “-i”}}},
bson.D{{“makers”, maker}},
}}
I use two different pipeline, the countPipeline to count of the products, the second to gets the products. To have the count we must add other pipeline:
var countPipeline mongo.Pipeline
var productsPipeline mongo.Pipelinesubpipeline := bson.D{
{"$match", bson.D{{"$and",
bson.A{
bson.D{{"name", bson.M{"$regex": ".*" + initial + ".*", "$options": "-i"}}},
bson.D{{"makers", maker}},
}}countPipeline = append(basePipeline, subpipeline)
countCondition := bson.D{{"$count", "numberOfProduct"}}
countPipeline = append(countPipeline, countCondition)
productsPipeline = append(basePipeline, subpipeline)
cur, err = GetDB().Collection("products").Aggregate(GetCtx(), countPipeline)// number of elements
var total intif err != nil {
fmt.Printf("[Debug] decode error %s", err)
panic(err)
} else {
for cur.Next(GetCtx()) {
dum := bson.M{"np": 0}
if err = cur.Decode(&dum); err != nil {
fmt.Printf("[Debug] decode error %s", err)
}
total = int(dum["numberOfProduct"].(int32))
}
}
Verify the page is in the range of the pages
// number of pagepages := total / 10if (total % 10) > 0 {
pages++
}jumpPage, conError := strconv.Atoi(page)if pages == 0 || conError != nil || jumpPage > pages {
finalResult := bson.M{"products": result, "productsCount": 0, "pages": 0}
return finalResult
}
Finally to gets the elements of the page:
result := []bson.M{}
var nProducts = 0// get elements
jumpPagePipeline := bson.D{{"$skip", jumpPage}}
limitPipeline := bson.D{{"$limit", 10}}productsPipeline = append(productsPipeline, jumpPagePipeline)
productsPipeline = append(productsPipeline, limitPipeline)cur, err = GetDB().Collection("products").Aggregate(GetCtx(), productsPipeline)// number of elementsif err != nil {
fmt.Printf("[Debug] decode error %s", err)
panic(err)
} else {
for cur.Next(GetCtx()) {
dum := bson.M{}
//var resultDecode bson.M
if err = cur.Decode(&dum); err != nil {
fmt.Printf("[Debug] decode error %s", err)
}
result = append(result, dum)
nProducts++
}
}finalResult := bson.M{"products": result, "productsCount": nProducts}
I used jumpedPipeline to jump to the page and limit to get only 10 elemets for page.
This example is not the better way to do the pagination, but it can be helpful to understand how build complex query.
For some better code you can see:
https://github.com/gobeam/mongo-go-pagination (it’s not my code)