Intro
Sometimes when you google for this, the answer is not quite clear and I also often forget how to do this.
Scenario
Imagine the following dataset in a mongodb collection
1
2
3
4
5
6
|
{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }
|
And we want to know the total count of prodcuts by order status.
Group
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
|
type OrderStatusTotal struct {
ID string `bson:"_id"`
Total int `bson:"total"`
}
pipelineResult := make([]OrderStatusTotal, 0)
pipeline := make([]bson.M, 0)
groupStage := bson.M{
"$group": bson.M{
"_id": "$status",
"total": bson.M{"$sum": 1},
},
}
pipeline = append(pipeline, groupStage)
data, err := collection.Aggregate(ctx, pipeline)
if err != nil {
log.Println(err.Error())
fmt.Errorf("failed to execute aggregation %s", err.Error())
return
}
err = data.All(ctx, &pipelineResult)
if err != nil {
log.Println(err.Error())
fmt.Errorf("failed to decode results", err.Error())
return
}
fmt.Printf("%+v\n", pipelineResult)
}
|
Group And Match
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
|
type OrderStatusTotal struct {
ID string `bson:"_id"`
Total int `bson:"total"`
}
pipelineResult := make([]OrderStatusTotal, 0)
pipeline := make([]bson.M, 0)
groupStage := bson.M{
"$group": bson.M{
"_id": "$status",
"total": bson.M{"$sum": 1},
},
}
matchStage := bson.M{
"$match": bson.M{
"cust_id": "abc1",
},
}
pipeline = append(pipeline, matchStage,groupStage)
data, err := collection.Aggregate(ctx, pipeline)
if err != nil {
log.Println(err.Error())
fmt.Errorf("failed to execute aggregation %s", err.Error())
return
}
err = data.All(ctx, &pipelineResult)
if err != nil {
log.Println(err.Error())
fmt.Errorf("failed to decode results", err.Error())
return
}
fmt.Printf("%+v\n", pipelineResult)
|
Notes
-
This is a super simple example, do not use in production
-
In order to avoid many external dependencies I always create custom types for querying mongodb, e.g
type DBQuery map[string]interface{}
-
Avoid using empty interfaces, this only leads to nil pointers and type assertions
-
Mongo aggregation docs
-
Feedbacks are always welcome :)
Full example can be found here