Around Go: MongoDB and Redis · 3 MIN READ
MongoDB: one client, explicit deadlines and typed documents
Connect with the Go v2 driver and separate construction, readiness, request work and cleanup.
MongoDB stores BSON documents and the Go driver manages discovery and pools for the deployment. A collection handle is not a new physical connection. Reuse a client across requests, model the fields the application owns, and keep network setup outside request-time package initialization.
Around Go: data stores · A MAP OF THE IDEA
- One shared client
- Bounded readiness
- Typed operation
- Bounded cleanup
Useful when
- Connect with the Go v2 driver and separate construction, readiness, request work and cleanup.
Watch out
- Connect configures a client; a bounded Ping separately tests current server readiness. Neither promises that future network operations cannot fail or time out.
Implementation & operation cost: One shared client owns pools and topology monitoring; each additional service instance multiplies that connection demand.
Construct the client and probe readiness
The example uses go.mongodb.org/mongo-driver/v2, with v2.3.1 as a reproducible example pin. Connect constructs the client; a successful Ping is separate evidence that a server is reachable. In a native development checkout, obtain the URI from configuration and use the deployment’s required authentication and TLS.
client, err := mongo.Connect(options.Client().ApplyURI(uri).SetMaxPoolSize(16))
if err != nil { return err }
probe, cancel := context.WithTimeout(ctx, 2*time.Second)
err = client.Ping(probe, readpref.Primary())
cancel()
if err != nil {
cleanup, stop := context.WithTimeout(context.Background(), time.Second)
defer stop()
_ = client.Disconnect(cleanup)
return err
}The fragment belongs to a startup function returning error and imports context, time, mongo, mongo/options and mongo/readpref from the v2 driver. The pool size is illustrative, not a production sizing recommendation.
Decode into a deliberate schema
Use BSON tags and explicit field types instead of letting every layer pass an unstructured map. Validate external input before constructing a query. ErrNoDocuments is an expected absence case when the contract allows it; it is different from a timeout, authorization failure or decode error.
type Note struct {
ID bson.ObjectID `bson:"_id,omitempty"`
Tenant string `bson:"tenant"`
Body string `bson:"body"`
}
var note Note
err := notes.FindOne(ctx, bson.D{{Key: "tenant", Value: tenant}, {Key: "_id", Value: id}}).Decode(¬e)
if errors.Is(err, mongo.ErrNoDocuments) { return ErrNotFound }
if err != nil { return fmt.Errorf("load note: %w", err) }notes is a collection from the shared client; tenant and id come from validated application inputs. The application defines ErrNotFound. An omitted tenant predicate could become a data-isolation bug even if the database query is fast.
Use separate lifetimes
Every request operation should inherit a bounded caller context. Startup probes and final Disconnect need their own lifetimes; do not reuse an already canceled request context for cleanup. These native service snippets are reading material: GopherForge does not add remote MongoDB sockets to its WASI execution sandbox.
TAKE THIS WITH YOU
Reuse a configured v2 client, prove readiness separately, decode explicit BSON models and distinguish absence from infrastructure failures.
Check your understanding
What does a successful mongo.Connect call establish?
Go to the source
Progress stays in this browser. No account needed.