forked from gobeam/mongo-go-pagination
/
main.go
155 lines (136 loc) · 4.85 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"github.com/userplant/mongopagination"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Product struct
type Product struct {
Id primitive.ObjectID `json:"_id,omitempty" bson:"_id"`
Name string `json:"name,omitempty" bson:"name"`
Quantity float64 `json:"quantity,omitempty" bson:"quantity"`
Price float64 `json:"price,omitempty" bson:"price"`
}
func insertExamples(db *mongo.Database) (insertedIds []interface{}, err error) {
var data []interface{}
for i := 0; i < 30; i++ {
data = append(data, bson.M{
"name": fmt.Sprintf("product-%d", i),
"quantity": float64(i),
"price": float64(i*10 + 5),
})
}
result, err := db.Collection("products").InsertMany(
context.Background(), data)
if err != nil {
return nil, err
}
return result.InsertedIDs, nil
}
var dbConnection *mongo.Database
func main() {
// Establishing mongo db connection
ctx := context.Background()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://127.0.0.1:27017/"))
if err != nil {
panic(err)
}
dbConnection = client.Database("myaggregate")
_, insertErr := insertExamples(client.Database("myaggregate"))
if insertErr != nil {
panic(insertErr)
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Testing pagination go to http://localhost:8081/normal-pagination?page=1&limit=10 to beign testing")
})
http.HandleFunc("/normal-pagination", func(w http.ResponseWriter, r *http.Request) {
convertedPageInt, convertedLimitInt := getPageAndLimit(r)
// Example for Normal Find query
filter := bson.M{}
limit := int64(convertedLimitInt)
page := int64(convertedPageInt)
collection := dbConnection.Collection("products")
projection := bson.D{
{"name", 1},
{"quantity", 1},
}
// Querying paginated data
// If you want to do some complex sort like sort by score(weight) for full text search fields you can do it easily
// sortValue := bson.M{
// "$meta" : "textScore",
// }
// paginatedData, err := mongopagination.New(collection).Context(ctx).Limit(limit).Page(page).Sort("score", sortValue)...
var products []Product
paginatedData, err := mongopagination.New(collection).Context(ctx).Limit(limit).Page(page).Sort("price", -1).Sort("quantity", -1).Select(projection).Filter(filter).Decode(&products).Find()
if err != nil {
panic(err)
}
payload := struct {
Data []Product `json:"data"`
Pagination mongopagination.PaginationData `json:"pagination"`
}{
Pagination: paginatedData.Pagination,
Data: products,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(payload)
})
http.HandleFunc("/aggregate-pagination", func(w http.ResponseWriter, r *http.Request) {
convertedPageInt, convertedLimitInt := getPageAndLimit(r)
collection := dbConnection.Collection("products")
//Example for Aggregation
limit := int64(convertedLimitInt)
page := int64(convertedPageInt)
//match query
match := bson.M{"$match": bson.M{"quantity": bson.M{"$gt": 0}}}
//
//group query
projectQuery := bson.M{"$project": bson.M{"_id": 1, "name": 1, "quantity": 1}}
// you can easily chain function and pass multiple query like here we are passing match
// query and projection query as params in Aggregate function you cannot use filter with Aggregate
// because you can pass filters directly through Aggregate param
aggPaginatedData, err := mongopagination.New(collection).Context(ctx).Limit(limit).Page(page).Sort("price", -1).Aggregate(match, projectQuery)
if err != nil {
panic(err)
}
var aggProductList []Product
for _, raw := range aggPaginatedData.Data {
var product *Product
if marshallErr := bson.Unmarshal(raw, &product); marshallErr == nil {
aggProductList = append(aggProductList, *product)
}
}
payload := struct {
Data []Product `json:"data"`
Pagination mongopagination.PaginationData `json:"pagination"`
}{
Pagination: aggPaginatedData.Pagination,
Data: aggProductList,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(payload)
})
fmt.Println("Application started on port http://localhost:8081")
log.Fatal(http.ListenAndServe(":8081", nil))
}
func getPageAndLimit(r *http.Request) (convertedPageInt int, convertedLimitInt int) {
queryPageValue := r.FormValue("page")
if queryPageValue != "" {
convertedPageInt, _ = strconv.Atoi(queryPageValue)
}
queryLimitValue := r.FormValue("limit")
if queryLimitValue != "" {
convertedLimitInt, _ = strconv.Atoi(queryLimitValue)
}
return convertedPageInt, convertedLimitInt
}