I'm trying to implement a mongodb pagination and this part is ok I got my limit and skip data BUT I wanted to have total of my element without make a second request.
I use aggregate with pipeline to populate some data so it's required to use aggregate.
In fact I'd like to decode my mongo result to something like that:
type exemple struct {
Orders []Order
Total int
}
I don't know if it's possible without make two request I tried to test somes thing as:
bson.D{
primitive.E{Key: "$facet", Value: bson.D{
primitive.E{Key: "orders", Value: []bson.D{
{primitive.E{Key: "$skip", Value: p.Skip}},
{primitive.E{Key: "$limit", Value: p.Limit}},
}},
primitive.E{Key: "totalCount", Value: []bson.D{
{primitive.E{Key: "$group", Value: bson.D{
primitive.E{Key: "_id", Value: nil},
primitive.E{Key: "count", Value: bson.D{
primitive.E{Key: "$sum", Value: 1},
}},
}}},
}},
}},
}
This work but only decode :
type exemple struct {
Orders []Order `bson:"orders" json:"orders"`
TotalCount []map[string]interface{} `bson:"totalCount" json:"totalCount"`
}
and I have to decode with []exemple as:
var test []exemple
if err = curs.All(r.ctx, &test); err != nil {
return err
}
So to get my data I have to do some fmt.Println(test[0].TotalCount) and it's horrible so I think there are a better way ..
And I think I understand a $project so I'd to recreate my schema data but is so fastidious and not really nice.
I also tried this:
{primitive.E{Key: "$count", Value: "count"}},
{primitive.E{Key: "$skip", Value: p.Skip}},
{primitive.E{Key: "$limit", Value: p.Limit}},
But this try give for every data a count key with every data in my DB.
Sorry for this unclear question I don't really know how to explain this problem correctly and it's probably the reason why I don't find answer.
--------------------- EDIT ---------------------
After tests I found something working but if someone have a better solution I'm listening :
I add that to my pipeline :
bson.D{
primitive.E{Key: "$facet", Value: bson.D{
primitive.E{Key: "orders", Value: []bson.D{
{primitive.E{Key: "$skip", Value: 10}},
{primitive.E{Key: "$limit", Value: 10}},
}},
primitive.E{Key: "totalCount", Value: []bson.D{
{primitive.E{Key: "$count", Value: "count"}},
}},
}},
}
and map the result of Aggregate function to :
resp := struct {
Orders []Order `bson:"orders" json:"orders"`
TotalCount []map[string]interface{} `bson:"totalCount" json:"totalCount"`
}{}
My error before that was to use cursor.All() instead of a for loop to cursor.Next() and then decode(&resp) into the loop:
for curs.Next(r.ctx) {
if err = curs.Decode(&resp); err != nil {
log.Println(err)
}
}
now I'm able to work with my resp like resp.Orders or resp.TotalCount.
But somes questions are still here:
- can I improved the TotalCount ? Because Actually it's a []map[string]interface{} so it's paintfull to work with.
Output: [map[count:5]], expected: map[count:5]
- for lookups other collection, I add this []bson.D to my pipeline (in my case)
[]bson.D{
{primitive.E{Key: "$lookup", Value: bson.D{primitive.E{Key: "from", Value: "users"}, primitive.E{Key: "localField", Value: "relationShip.customer"}, primitive.E{Key: "foreignField", Value: "_id"}, primitive.E{Key: "as", Value: "relationShip.included.customer"}}}},
{primitive.E{Key: "$unwind", Value: bson.D{primitive.E{Key: "path", Value: "$relationShip.included.customer"}, primitive.E{Key: "preserveNullAndEmptyArrays", Value: false}}}},
{primitive.E{Key: "$lookup", Value: bson.D{primitive.E{Key: "from", Value: "users"}, primitive.E{Key: "localField", Value: "relationShip.editor"}, primitive.E{Key: "foreignField", Value: "_id"}, primitive.E{Key: "as", Value: "relationShip.included.editor"}}}},
{primitive.E{Key: "$unwind", Value: bson.D{primitive.E{Key: "path", Value: "$relationShip.included.editor"}, primitive.E{Key: "preserveNullAndEmptyArrays", Value: false}}}},
}
that works BUT I add this BEFORE my paginate so mongodb lookups for entire collection? It is possible to add it after paginate for maybe improved performance?