So I have this mongo db query which works fine:
db.levels.aggregate([{
$match: {
"_id": {$lt: ObjectId("56410480f91e505237902dae")}
},
},
{ $group:
{
"_id": {"title": "Level 11"},
"totalAmount": { $sum: "$rewardCoins"}
}
}
])
It should get all rows before give id and based on rewardCoins calculate sum.
Now with mgo in golang I'm strugling to get this working... I'm going with pipe but my resultset is empty.
pipe := c.Pipe([]bson.M{{"$match": bson.M{"_id": bson.M{"$lt": level.ID}},
"$group": bson.M{"_id":"$title", "totalReward": bson.M{"$sum": "$rewardCoins"}}}})
res :=[]bson.M{}
pipe.All(&res)
What I'm doing wrong here ? Thanks.
UPDATE
Here is how my simple rows look like in db:
{ "_id" : ObjectId("5613f5ad153678d113d01f4a"), "title" : "Level 1", "rewardCoins" : NumberLong(1000) }
{ "_id" : ObjectId("56159796153678d113d02d60"), "title" : "Level 2", "rewardCoins" : NumberLong(50000) }
The structure in Go isn't the same as in the other language. If you hit Enter after every brace or comma, add commas where Go wants them, and run go fmt
, you get one bson.M
:
pipe := c.Pipe(
[]bson.M{
{
"$match": bson.M{
"_id": bson.M{
"$lt": level.ID,
},
},
"$group": bson.M{
"_id": "$title",
"totalReward": bson.M{
"$sum": "$rewardCoins",
},
},
},
},
)
Another way to see it is that there's no }, {
before $group
in the Go, whereas there is in the JSON-y version.
Indenting this way seems like a good idea in general; the eyes can get lost in a sea of brackets otherwise.
I might be wrong but looks like only one possible problem in your query is the type of level.ID
. If it is string you should convert it to ObjectID
with bson.ObjectIdHex(string)
function.
Update 2
Took example documents but made custom _id
s to be sure that they are in order. If on your database this code doesn't work that mean your documents _id
are not in order. I.e. you've added 'Level 11' before 'Level 1', or different Levels were added on different machines as ObjectID
has timestamp and machine ID in it and shouldn't be used as sorting field to be honest. As someone suggested in your another question - just add level
numeric field and $match
by it to be sure that you are selecting right documents.
package main
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"fmt"
)
func main() {
session, err := mgo.Dial("mongodb://souser:123456@ds055855.mlab.com:55855/catalog")
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("catalog").C("levels")
/*
Database structure
{ "_id" : ObjectId("56410480f91e505237902dab"), "title" : "Level 8", "rewardCoins" : NumberLong(25)}
{ "_id" : ObjectId("56410480f91e505237902dac"), "title" : "Level 9", "rewardCoins" : NumberLong(40)}
{ "_id" : ObjectId("56410480f91e505237902dad"), "title" : "Level 10", "rewardCoins" : NumberLong(55)}
{ "_id" : ObjectId("56410480f91e505237902dae"), "title" : "Level 11", "rewardCoins" : NumberLong(70)}
*/
pipe := c.Pipe(
[]bson.M{
bson.M{
"$match": bson.M{
"_id": bson.M{
"$lt": bson.ObjectIdHex("56410480f91e505237902dae"),
},
},
},
bson.M{
"$group": bson.M{
"_id": bson.M {
"title": "Level 11",
},
"totalAmount": bson.M{"$sum": "$rewardCoins"},
},
},
},
)
result := []bson.M{}
err = pipe.All(&result) // [map[_id:map[title:Level 11] totalAmount:120]]
if err != nil {
panic(err)
}
fmt.Printf("%d", result[0]["totalAmount"]) // 120
}