I having a couple of structs, Products and Categories. I have 2 functions listed below that have identical logic just different structs that are being used and returned. Is there anyway I can abstract out the struct data types and use the same logic in a single function called GetObjects
?
func GetCategories(collection *mongo.Collection) []Category {
ctx := context.Background()
cats := []Category{}
cur, err := collection.Find(ctx, bson.M{})
if err != nil {
log.Fatal("Error: ", err)
}
for cur.Next(context.TODO()) {
var cat Category
err = cur.Decode(&cat)
if err != nil {
log.Fatal(err)
}
cats = append(cats, cat)
}
return cats
}
func GetProducts(collection *mongo.Collection) []Product {
ctx := context.Background()
prods := []Product{}
cur, err := collection.Find(ctx, bson.M{})
if err != nil {
log.Fatal("Error: ", err)
}
for cur.Next(context.TODO()) {
var prod Product
err = cur.Decode(&prod)
if err != nil {
log.Fatal(err)
}
prods = append(prods, prod)
}
return prods
}
You could create a generalized GetObjs()
if you would pass in the destination where you want the results to be loaded.
Something like:
func GetObjs(c *mongo.Collection, dst interface{})
And callers are responsible to pass a ready slice or a pointer to a slice variable where results will be stored.
Also note that context.Context
should be passed and not created arbitrarily inside the function:
func GetObjs(ctx context.Context, c *mongo.Collection, dst interface{})
Also, errors should be returned and not "swallowed", so if one occurs, it can be dealt with appropriately at the caller:
func GetObjs(ctx context.Context, c *mongo.Collection, dst interface{}) error
Also, if you need all results, you don't need to iterate over them and decode all one-by-one. Just use Cursor.All()
.
This is how the "improved" GetObjs()
could look like:
func GetObjs(ctx context.Context, c *mongo.Collection, dst interface{}) error {
cur, err := c.Find(ctx, bson.M{})
if err != nil {
return err
}
return cur.All(ctx, dst)
}
(Although this became quite simple, not sure it warrants its own existence.)
And this is how you could use it:
ctx := ... // Obtain context, e.g. from the request: r.Context()
c := ... // Collection you want to query from
var cats []Category
if err := GetObjs(ctx, c, &cats); err != nil {
// Handle error
return
}
// Use cats
var prods []Product
if err := GetObjs(ctx, c, &prods); err != nil {
// Handle error
return
}
// Use prods