Home

Go MongoDB Model with Enum Validation for Brand Field

67 views

Sure, let's define a MongoDB model in Go where the Brand field can only be either "porta" or "boss". We'll follow the same steps as before:

  1. Define a custom type Brand.
  2. Define the possible values for Brand.
  3. Implement BSON marshalling and unmarshalling for the custom type.
  4. Define the MongoDB model that includes the Brand field.

Here is the complete code:

package main

import (
    "context"
    "fmt"
    "os"

    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo/bson/bsontype"
)

// Brand type represents an enum
type Brand string

const (
    BrandPorta Brand = "porta"
    BrandBoss  Brand = "boss"
)

// Implement BSON marshalling and unmarshalling
func (b Brand) MarshalBSONValue() (bsontype.Type, []byte, error) {
    return bson.MarshalValue(string(b))
}

func (b *Brand) UnmarshalBSONValue(t bsontype.Type, data []byte) error {
    var str string
    if err := bson.UnmarshalValue(t, data, &str); err != nil {
        return err
    }
    *b = Brand(str)
    return nil
}

// Document represents a MongoDB document
type Document struct {
    ID    string `bson:"_id,omitempty"`
    Name  string `bson:"name,omitempty"`
    Brand Brand  `bson:"brand,omitempty"`
}

func main() {
    // MongoDB configuration
    uri := "mongodb://localhost:27017"
    clientOpts := options.Client().ApplyURI(uri)
    client, err := mongo.Connect(context.TODO(), clientOpts)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to connect to MongoDB: %v\n", err)
        os.Exit(1)
    }
    defer func() {
        if err := client.Disconnect(context.TODO()); err != nil {
            fmt.Fprintf(os.Stderr, "Failed to disconnect from MongoDB: %v\n", err)
        }
    }()

    collection := client.Database("testdb").Collection("documents")

    // Create a document with Brand "porta"
    doc := Document{
        Name:  "Sample Document",
        Brand: BrandPorta,
    }

    // Insert the document
    insertResult, err := collection.InsertOne(context.TODO(), doc)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to insert document: %v\n", err)
        os.Exit(1)
    }
    fmt.Printf("Inserted document with ID: %v\n", insertResult.InsertedID)

    // Retrieve the document
    filter := bson.M{"name": "Sample Document"}
    var retrievedDoc Document
    err = collection.FindOne(context.TODO(), filter).Decode(&retrievedDoc)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to find document: %v\n", err)
        os.Exit(1)
    }
    fmt.Printf("Retrieved document: %+v\n", retrievedDoc)
}

Explanation:

  1. Brand Type: Defined a new type Brand which represents the enum.
  2. Enum Values: Defined two constants BrandPorta and BrandBoss representing the allowed values for the Brand type.
  3. BSON Handling: Implemented the MarshalBSONValue and UnmarshalBSONValue methods to correctly convert between the Brand type and BSON.
  4. Document Model: The Document struct includes an ID, Name, and Brand field.
  5. Database Operations: Connected to a MongoDB instance, inserted a document with a Brand value, and retrieved it to demonstrate the proper handling of the enum in a MongoDB context.

This ensures that the Brand field in the model can only have values defined by the Brand type.