Go interface for MongoDB store for fields like bson.D

Viewed 35

I've got a Go app which uses MongoDB data storage, but still want it to be easy to switch out drivers (to PostgresSQL, who knows) and to test.

So I'm passing around a Storage interface which describes what a storage should do.

type Storage interface {
    InsertOne(ctx context.Context, collection string, document interface{}) error
    FindOne(ctx context.Context, collection string, filters map[string]string) (map[string]interface{}, error)
}

Then I've got a MongoDB implementation of that:

type Mongo struct {
    Client   *mongo.Client
    Database string
}

func (m *Mongo) InsertOne(ctx context.Context, collection string, document interface{}) error {
    _, err := m.Client.Database(m.Database).Collection(collection).InsertOne(ctx, document)
    if err != nil {
        return err
    }
    return nil
}

func (m *Mongo) FindOne(ctx context.Context, collection string, filters map[string]string) (map[string]interface{}, error) {
    var result bson.M
    var filter bson.D
    for k, v := range filters {
        filter = append(filter, bson.E{
            Key:   k,
            Value: v,
        })
    }
    err := m.Client.Database(m.Database).Collection(collection).FindOne(ctx, filter).Decode(&result)
    if err != nil {
        return nil, err
    }
    resultMap := make(map[string]interface{}, len(result))
    for k, v := range result {
        resultMap[k] = v
    }
    return resultMap, nil
}

I'm using bson.D to filter Mongo, so passing in filters map[string]string and converting it to bson.D.

This works fine when the filter is something simple like bson.D{{"title", "The Room"}}, simply pass it to the function like map[string]string{"title": "The Room"}.

But it's not so simple when it's a more complex filter like bson.D{{"population", bson.D{{"$lte", 500}}}}

This approach is not looking that good at the moment, feels like I'm very limited in what I can do.

So I'm looking for advice on a better way to do this.

0 Answers
Related