Mongo Aggregate with total and results, converting to struct

I am working in golang and the mongo driver. I am having a tough time understanding the proper way to go about the following

  1. Count the data (Done)
  2. Filter the data (Done)
  3. Decode to Count + Results (Don’t understand)

I find that my below code seems a bit hacked. Is this the expected path to work with mongodb aggreegates?

func (in *Instance) ListProjects(ctx context.Context, orgID string, filters []*Filter, offset int32, limit int32) ([]*model.Project, int, error) {
	in.logger.Info("list_projects called with project_name")

	filter := ParseFilters(filters, in.config.Filters.AuthorizedFields)
	off := int64(offset)
	lim := int64(limit)

	pipeline := mongo.Pipeline{
		{{Key: "$match", Value: filter}},
		{{Key: "$facet", Value: bson.M{
			"total": []bson.M{{"$count": "total"}},
			"results": []bson.M{
				{"$skip": off},
				{"$limit": lim},
			},
		}}},
	}
	cur, err := in.db.
		Database(in.config.Database.Name).
		Collection("projects").
		Aggregate(ctx, pipeline)
	if err != nil {
		return nil, 0, err
	}
	defer cur.Close(context.TODO())

	projects := make([]*model.Project, 0)
	total := 0
	for cur.Next(context.TODO()) {
	    var result bson.M
	    err := cur.Decode(&result)
	    if err != nil {
	        in.logger.Error(err)
	        continue
	    }
	    for _, v := range result {
	        switch vv := v.(type) {
	        case bson.M:
	            for key, val := range vv {
	                if key == "total" {
	                    total = int(val.(float64))
	                } else if key == "results" {
	                    results := val.([]interface{})
	                    for _, item := range results {
	                        data := item.(bson.M)
	                        dataD, err := bson.Marshal(data)
	                        if err != nil {
	                            in.logger.Error(err)
	                            continue
	                        }
	                        var project model.Project
	                        err = bson.Unmarshal(dataD, &project)
	                        if err != nil {
	                            in.logger.Error(err)
	                            continue
	                        }
	                        projects = append(projects, &project)
	                    }
	                }
	            }
	        }
	    }
	}
	return projects, total, nil
}
1 Like

Hi @Zachary_Schulze ,

What is the specific issues you experience the code seems to use facet for one key. Fir results the other for counts.

Overall seems correct

Thanks
Pavel