gomongo

January 27, 2026 · View on GitHub

Go library for parsing and executing MongoDB shell syntax using the native MongoDB driver.

Overview

gomongo parses MongoDB shell commands (e.g., db.users.find()) and executes them using the Go MongoDB driver, eliminating the need for external mongosh CLI.

Installation

go get github.com/bytebase/gomongo

Usage

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/bytebase/gomongo"
    "go.mongodb.org/mongo-driver/v2/bson"
    "go.mongodb.org/mongo-driver/v2/mongo"
    "go.mongodb.org/mongo-driver/v2/mongo/options"
)

func main() {
    ctx := context.Background()

    // Connect to MongoDB
    client, err := mongo.Connect(options.Client().ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        log.Fatal(err)
    }
    defer client.Disconnect(ctx)

    // Create gomongo client
    gc := gomongo.NewClient(client)

    // Execute MongoDB shell commands
    result, err := gc.Execute(ctx, "mydb", `db.users.find({ age: { $gt: 25 } })`)
    if err != nil {
        log.Fatal(err)
    }

    // Result.Value contains []any - type depends on operation
    // For find(), each element is bson.D
    for _, val := range result.Value {
        doc, ok := val.(bson.D)
        if !ok {
            log.Printf("unexpected type %T\n", val)
            continue
        }
        fmt.Printf("%+v\n", doc)
    }

    // For countDocuments(), single element is int64
    countResult, err := gc.Execute(ctx, "mydb", `db.users.countDocuments({})`)
    if err != nil {
        log.Fatal(err)
    }
    count, ok := countResult.Value[0].(int64)
    if !ok {
        log.Fatalf("unexpected type %T\n", countResult.Value[0])
    }
    fmt.Printf("Count: %d\n", count)
}

Execute Options

The Execute method accepts optional configuration:

WithMaxRows

Limit the maximum number of rows returned by find() and countDocuments() operations. This is useful to prevent excessive memory usage or network traffic from unbounded queries.

// Cap results at 1000 rows
result, err := gc.Execute(ctx, "mydb", `db.users.find()`, gomongo.WithMaxRows(1000))

Behavior:

  • If the query includes .limit(N), the effective limit is min(N, maxRows)
  • Query limit 50 + MaxRows 1000 → returns up to 50 rows
  • Query limit 5000 + MaxRows 1000 → returns up to 1000 rows
  • aggregate() operations are not affected (use $limit stage instead)

Output Format

Results are returned as native Go types in Result.Value (a []any slice). Use Result.Operation to determine the expected type:

OperationValue Type
OpFind, OpAggregate, OpGetIndexes, OpGetCollectionInfosEach element is bson.D
OpFindOne, OpFindOneAnd*0 or 1 element of bson.D
OpCountDocuments, OpEstimatedDocumentCountSingle int64
OpDistinctElements are the distinct values
OpShowDatabases, OpShowCollections, OpGetCollectionNamesEach element is string
OpInsert*, OpUpdate*, OpReplace*, OpDelete*Single bson.D with result
OpCreateIndexSingle string (index name)
OpDropIndex, OpDropIndexes, OpCreateCollection, OpDropDatabase, OpRenameCollectionSingle bson.D with {ok: 1}
OpDropSingle bool (true)

Command Reference

Milestone 1: Read Operations + Utility + Aggregation (Current)

Utility Commands

CommandSyntaxStatus
show dbsshow dbsSupported
show databasesshow databasesSupported
show collectionsshow collectionsSupported
db.getCollectionNames()db.getCollectionNames()Supported
db.getCollectionInfos()db.getCollectionInfos()Supported

Read Commands

CommandSyntaxStatusNotes
db.collection.find()find(query, projection)Supportedoptions deferred
db.collection.findOne()findOne(query, projection)Supported
db.collection.countDocuments()countDocuments(filter)Supportedoptions deferred
db.collection.estimatedDocumentCount()estimatedDocumentCount()Supportedoptions deferred
db.collection.distinct()distinct(field, query)Supportedoptions deferred
db.collection.getIndexes()getIndexes()Supported

Cursor Modifiers

MethodSyntaxStatus
cursor.limit()limit(number)Supported
cursor.skip()skip(number)Supported
cursor.sort()sort(document)Supported
cursor.count()count()Deprecated - use countDocuments()

Aggregation

CommandSyntaxStatusNotes
db.collection.aggregate()aggregate(pipeline)Supportedoptions deferred

Object Constructors

ConstructorSupported SyntaxUnsupported Syntax
ObjectId()ObjectId(), ObjectId("hex")new ObjectId()
ISODate()ISODate(), ISODate("string")new ISODate()
Date()Date(), Date("string"), Date(timestamp)new Date()
UUID()UUID("hex")new UUID()
NumberInt()NumberInt(value)new NumberInt()
NumberLong()NumberLong(value)new NumberLong()
NumberDecimal()NumberDecimal("value")new NumberDecimal()
Timestamp()Timestamp(t, i)new Timestamp()
BinData()BinData(subtype, base64)
RegExp()RegExp("pattern", "flags"), /pattern/flags

Milestone 2: Write Operations (Current)

Insert Commands

CommandSyntaxStatus
db.collection.insertOne()insertOne(document, options)Supported
db.collection.insertMany()insertMany(documents, options)Supported

Update Commands

CommandSyntaxStatus
db.collection.updateOne()updateOne(filter, update, options)Supported
db.collection.updateMany()updateMany(filter, update, options)Supported
db.collection.replaceOne()replaceOne(filter, replacement, options)Supported

Delete Commands

CommandSyntaxStatus
db.collection.deleteOne()deleteOne(filter, options)Supported
db.collection.deleteMany()deleteMany(filter, options)Supported

Atomic Find-and-Modify Commands

CommandSyntaxStatus
db.collection.findOneAndUpdate()findOneAndUpdate(filter, update, options)Supported
db.collection.findOneAndReplace()findOneAndReplace(filter, replacement, options)Supported
db.collection.findOneAndDelete()findOneAndDelete(filter, options)Supported

Write Operation Options

OptionApplies ToDescription
writeConcernAll write opsWrite concern settings (w, j, wtimeout*)
bypassDocumentValidationInsert, Update, Replace, FindOneAndUpdate/ReplaceSkip schema validation
commentAll write opsComment for server logs
orderedinsertManyExecute inserts sequentially (default: true)
upsertUpdate, Replace, FindOneAndUpdate/ReplaceInsert if no match found
hintUpdate, Replace, Delete, FindOneAnd*Force index usage
collationUpdate, Replace, Delete, FindOneAnd*String comparison rules
arrayFiltersupdateOne, updateMany, findOneAndUpdateArray element filtering
letUpdate, Replace, Delete, FindOneAnd*Variables for expressions
sortupdateOne, replaceOne, FindOneAnd*Document selection order
projectionFindOneAnd*Fields to return
returnDocumentFindOneAndUpdate/ReplaceReturn "before" or "after"

*Note: wtimeout is parsed but ignored as it's not supported in MongoDB Go driver v2.

Milestone 3: Administrative Operations

Index Management

CommandSyntaxStatus
db.collection.createIndex()createIndex(keys, options)Supported
db.collection.createIndexes()createIndexes(indexSpecs)Not yet supported
db.collection.dropIndex()dropIndex(index)Supported
db.collection.dropIndexes()dropIndexes()Supported

Collection Management

CommandSyntaxStatus
db.createCollection()db.createCollection(name, options)Supported
db.collection.drop()drop()Supported
db.collection.renameCollection()renameCollection(newName, dropTarget)Supported
db.dropDatabase()db.dropDatabase()Supported

Database Information

CommandSyntaxStatus
db.stats()db.stats()Not yet supported
db.collection.stats()stats()Not yet supported
db.serverStatus()db.serverStatus()Not yet supported
db.serverBuildInfo()db.serverBuildInfo()Not yet supported
db.version()db.version()Not yet supported
db.hostInfo()db.hostInfo()Not yet supported
db.listCommands()db.listCommands()Not yet supported

Not Planned

The following categories are recognized but not planned for support:

CategoryReason
Database switching (use <db>, db.getSiblingDB())Database is set at connection time
Interactive cursor methods (hasNext(), next(), toArray())Not an interactive shell
JavaScript execution (forEach(), map())No JavaScript engine
Replication (rs.*)Cluster administration
Sharding (sh.*)Cluster administration
User/Role managementSecurity administration
Client-side encryptionSecurity feature
Atlas Stream Processing (sp.*)Atlas-specific
Native shell functions (cat(), load(), quit())Shell-specific

For deprecated methods (e.g., db.collection.insert(), db.collection.update()), gomongo returns actionable error messages directing users to modern alternatives.

Design Principles

  1. No database switching - Database is set at connection time only
  2. Not an interactive shell - No cursor iteration, REPL-style commands, or stateful operations
  3. Syntax translator, not validator - Arguments pass directly to the Go driver; the server validates
  4. Single syntax for constructors - Use ObjectId(), not new ObjectId()
  5. Clear error messages - Actionable guidance for unsupported or deprecated syntax