0

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
}
0

1 Answer 1

4

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
Sign up to request clarification or add additional context in comments.

1 Comment

sweet, thanks so much. I just learned go last week so am not as familiar with interfaces. Thanks again

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.