How to do MongoDB aggregation

Viewed 311

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?

0 Answers
Related