Working with databases is a fundamental part of backend development, particularly when you’re building applications that require persisting, querying, and updating data.
In Go, the official MongoDB driver provides a robust way to connect to and interact with MongoDB, a flexible NoSQL database that stores data in JSON-like documents.
In this tutorial, you won’t just learn how to connect Go to MongoDB. You’ll take it a step further by building a simple blog application. Along the way, you’ll learn how to perform essential CRUD (Create, Read, Update, Delete) operations and display your results using the Gin web framework.
Table of Contents
Prerequisites
Before you proceed, ensure that you have the following:
-
Basic knowledge of Go and its concepts
-
Go (version 1.24 or higher) installed
-
MongoDB Installed (running locally on port 27017)
-
Basic knowledge of NoSQL
Create a New Go Project
First, create a new Go project, change into the new project directory, and initialize a new Go module by running the following commands:
mkdir go-mongodb-integration
<span class="hljs-built_in">cd</span> go-mongodb-integrationgo
mod init go-mongodb
Next, install the MongoDB Go driver by running the following command:
go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/bson
The standard Go library includes the database/sql
package for working with SQL databases, but it doesn’t support MongoDB out of the box. To work with MongoDB in Go, you’ll use the official MongoDB driver, which provides everything you need to connect to and interact with a MongoDB database.
With the basic setup complete, let’s now examine basic operations in MongoDB.
Basic MongoDB Operations
In MongoDB, databases and collections are created automatically upon the first data insertion, adopting a “lazy creation” approach. Specifically, a database is created when you insert your first document, and a collection is likewise created when data is first inserted into it.
It’s important to note that functions like client.Database()
and db.Collection()
only generate references to these structures – they don’t create the actual database or collection until data is inserted.
Insert data into the collection
Let’s walk through how to insert a document into a collection in MongoDB.
First, open your project in a code editor, create a main.go
file, and add the following code:
<span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"context"</span>
<span class="hljs-string">"log"</span>
<span class="hljs-string">"time"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)
<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
ID primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
Name <span class="hljs-keyword">string</span> <span class="hljs-string">`bson:"name"`</span>
Age <span class="hljs-keyword">int</span> <span class="hljs-string">`bson:"age"`</span>
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
client, err := mongo.Connect(ctx, clientOptions)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
<span class="hljs-keyword">defer</span> client.Disconnect(ctx)
err = client.Ping(ctx, <span class="hljs-literal">nil</span>)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
db := client.Database(<span class="hljs-string">"test_db"</span>)
usersCollection := db.Collection(<span class="hljs-string">"users"</span>)
newUser := User{
Name: <span class="hljs-string">"John Doe"</span>,
Age: <span class="hljs-number">30</span>,
}
result, err := usersCollection.InsertOne(ctx, newUser)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
log.Printf(<span class="hljs-string">"Inserted user with ID: %vn"</span>, result.InsertedID)
}
In the code above, you define a User
struct that represents your document structure, then insert a new user document into the collection using the InsertOne
method. When you run this insert operation, MongoDB automatically creates both the test_db
database and the users
collection if they don’t already exist.
Execute the code by running:
go run main.go
You should see the response below, indicating that a user was inserted successfully.
Find documents in MongoDB
Now that you’ve inserted some data, it’s time to query the database and retrieve documents.
Update your main.go
file with the following code:
<span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"context"</span>
<span class="hljs-string">"fmt"</span>
<span class="hljs-string">"log"</span>
<span class="hljs-string">"time"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)
<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
ID primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
Name <span class="hljs-keyword">string</span> <span class="hljs-string">`bson:"name"`</span>
Age <span class="hljs-keyword">int</span> <span class="hljs-string">`bson:"age"`</span>
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
client, err := mongo.Connect(ctx, clientOptions)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
<span class="hljs-keyword">defer</span> client.Disconnect(ctx)
db := client.Database(<span class="hljs-string">"test_db"</span>)
usersCollection := db.Collection(<span class="hljs-string">"users"</span>)
cursor, err := usersCollection.Find(ctx, bson.M{})
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
<span class="hljs-keyword">defer</span> cursor.Close(ctx)
<span class="hljs-keyword">var</span> users []User
<span class="hljs-keyword">if</span> err = cursor.All(ctx, &users); err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
<span class="hljs-keyword">for</span> _, user := <span class="hljs-keyword">range</span> users {
fmt.Printf(<span class="hljs-string">"User: %s, Age: %d, ID: %sn"</span>, user.Name, user.Age, user.ID.Hex())
}
}
In the code above, you use the Find
method with an empty filter (`bson.M{}`) to retrieve all documents from the users
collection. Then, you use cursor.All
to decode all the results into a slice of User
structs.
Each document is printed to the terminal, showing the name, age, and ID of every user in the collection.
To run the code, use:
go run main.go
You should see the response below in your terminal.
Update documents in MongoDB
To update a document in your collection, modify your main.go
file as shown below:
<span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"context"</span>
<span class="hljs-string">"log"</span>
<span class="hljs-string">"time"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)
<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
ID primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
Name <span class="hljs-keyword">string</span> <span class="hljs-string">`bson:"name"`</span>
Age <span class="hljs-keyword">int</span> <span class="hljs-string">`bson:"age"`</span>
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
client, err := mongo.Connect(ctx, clientOptions)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
<span class="hljs-keyword">defer</span> client.Disconnect(ctx)
db := client.Database(<span class="hljs-string">"test_db"</span>)
usersCollection := db.Collection(<span class="hljs-string">"users"</span>)
<span class="hljs-keyword">var</span> userToUpdate User
err = usersCollection.FindOne(ctx, bson.M{<span class="hljs-string">"name"</span>: <span class="hljs-string">"John Doe"</span>}).Decode(&userToUpdate)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Println(<span class="hljs-string">"No user found to update"</span>)
} <span class="hljs-keyword">else</span> {
update := bson.M{
<span class="hljs-string">"$set"</span>: bson.M{
<span class="hljs-string">"name"</span>: <span class="hljs-string">"Jane Doe"</span>,
<span class="hljs-string">"age"</span>: <span class="hljs-number">25</span>,
},
}
result, err := usersCollection.UpdateOne(
ctx,
bson.M{<span class="hljs-string">"_id"</span>: userToUpdate.ID},
update,
)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
log.Printf(<span class="hljs-string">"Updated %v document(s)n"</span>, result.ModifiedCount)
}
}
In the code above, you first search for a user named “John Doe” using the FindOne
method. If a match is found, you use the UpdateOne
method to update their name and age. The $set
operator ensures that only the specified fields are updated, leaving the rest of the document unchanged.
Execute the code by running:
go run main.go
You should see output in your terminal indicating how many documents were updated.
Delete documents in MongoDB
To remove documents from a collection, you can use the DeleteOne
method. Update your main.go
file with the following code:
<span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"context"</span>
<span class="hljs-string">"log"</span>
<span class="hljs-string">"time"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)
<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
ID primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
Name <span class="hljs-keyword">string</span> <span class="hljs-string">`bson:"name"`</span>
Age <span class="hljs-keyword">int</span> <span class="hljs-string">`bson:"age"`</span>
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
client, err := mongo.Connect(ctx, clientOptions)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
<span class="hljs-keyword">defer</span> client.Disconnect(ctx)
db := client.Database(<span class="hljs-string">"test_db"</span>)
usersCollection := db.Collection(<span class="hljs-string">"users"</span>)
result, err := usersCollection.DeleteOne(ctx, bson.M{<span class="hljs-string">"name"</span>: <span class="hljs-string">"Jane Doe"</span>})
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
log.Printf(<span class="hljs-string">"Deleted %v document(s)n"</span>, result.DeletedCount)
}
In the code above, you use the DeleteOne
method to remove the first document that matches the filter { "name": "Jane Doe" }
.
You should see the result below in your terminal.
How to Build a Blog App with go-mongodb-driver and Gin
Now that you understand how to perform basic CRUD operations with MongoDB in Go, you’re ready to build a more complete application.
Start by creating a new directory for your project and initializing it as a Go module. Navigate to your chosen directory and run:
mkdir go-blog
<span class="hljs-built_in">cd</span> go-blog
go mod init blog
Next, install the required dependencies:
go get github.com/gin-gonic/gin
go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/bson
Your project will have the following structure:
go-blog/
├── main.go
├── handlers/
│ └── main.go
└── templates/
├── index.html
├── post.html
├── create.html
└── edit.html
Initialize the Gin application
To initialize a new Gin application, create a new main.go
file and add the below code snippet to it:
<span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"context"</span>
<span class="hljs-string">"log"</span>
<span class="hljs-string">"time"</span>
<span class="hljs-string">"blog/handlers"</span>
<span class="hljs-string">"github.com/gin-gonic/gin"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
client, err := mongo.Connect(ctx, clientOptions)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
<span class="hljs-keyword">defer</span> client.Disconnect(ctx)
err = client.Ping(ctx, <span class="hljs-literal">nil</span>)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
log.Fatal(err)
}
log.Println(<span class="hljs-string">"Connected to MongoDB!"</span>)
db := client.Database(<span class="hljs-string">"blog_db"</span>)
h := handlers.NewHandler(db)
router := gin.Default()
router.LoadHTMLGlob(<span class="hljs-string">"templates/*"</span>)
router.GET(<span class="hljs-string">"/"</span>, h.HomePage)
router.GET(<span class="hljs-string">"/post/:id"</span>, h.ViewPost)
router.GET(<span class="hljs-string">"/create"</span>, h.CreatePost)
router.GET(<span class="hljs-string">"/edit/:id"</span>, h.EditPost)
router.POST(<span class="hljs-string">"/save"</span>, h.SavePost)
router.GET(<span class="hljs-string">"/delete/:id"</span>, h.DeletePost)
log.Println(<span class="hljs-string">"Server starting on :8080..."</span>)
router.Run(<span class="hljs-string">":8080"</span>)
}
The code above sets up the MongoDB connection, initializes the Gin router, and registers your routes.
Create the HTML templates
Now, create the HTML templates for displaying the blog UI.
First, create a templates
directory and add the following files:
index.html:
<span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">title</span>></span>Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>></span>Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/create"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>></span>Create New Post<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">header</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"</span>></span>
{{range .}}
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-xl font-semibold mb-2 text-gray-800"</span>></span>{{.Title}}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span>
<span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600 mb-4 line-clamp-3"</span>></span>
{{if gt (len .Content) 150}}
{{slice .Content 0 150}}...
{{else}}
{{.Content}}
{{end}}
<span class="hljs-tag"></<span class="hljs-name">p</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-between items-center text-sm text-gray-500"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">span</span>></span>{{.CreatedAt.Format "Jan 02, 2006"}}<span class="hljs-tag"></<span class="hljs-name">span</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/post/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-500 hover:text-blue-700"</span>></span>Read More<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex border-t border-gray-200"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/edit/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-2 text-center text-sm text-gray-600 hover:bg-gray-100 border-r border-gray-200"</span>></span>Edit<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/delete/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-2 text-center text-sm text-red-600 hover:bg-gray-100"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"return confirm('Are you sure you want to delete this post?')"</span>></span>Delete<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
{{else}}
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-span-3 text-center py-12"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600 text-lg"</span>></span>No posts yet. <span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/create"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-500 hover:underline"</span>></span>Create one<span class="hljs-tag"></<span class="hljs-name">a</span>></span>!<span class="hljs-tag"></<span class="hljs-name">p</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
{{end}}
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
This template lists all blog posts and includes buttons to create, edit, or delete posts.
post.html:
<span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">title</span>></span>{{.Title}} | Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>></span>Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>></span>Back to Home<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">header</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-3xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-2xl font-bold mb-4 text-gray-800"</span>></span>{{.Title}}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center text-sm text-gray-500 mb-6"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">span</span>></span>Posted: {{.CreatedAt.Format "Jan 02, 2006"}}<span class="hljs-tag"></<span class="hljs-name">span</span>></span>
{{if ne .CreatedAt .UpdatedAt}}
<span class="hljs-tag"><<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mx-2"</span>></span>•<span class="hljs-tag"></<span class="hljs-name">span</span>></span>
<span class="hljs-tag"><<span class="hljs-name">span</span>></span>Updated: {{.UpdatedAt.Format "Jan 02, 2006"}}<span class="hljs-tag"></<span class="hljs-name">span</span>></span>
{{end}}
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"prose max-w-none"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-700 whitespace-pre-line"</span>></span>{{.Content}}<span class="hljs-tag"></<span class="hljs-name">p</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex border-t border-gray-200"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/edit/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-3 text-center text-blue-600 hover:bg-gray-100 border-r border-gray-200"</span>></span>Edit Post<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/delete/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-3 text-center text-red-600 hover:bg-gray-100"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"return confirm('Are you sure you want to delete this post?')"</span>></span>Delete Post<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
This template displays a single post.
create.html:
<span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">title</span>></span>Create New Post | Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>></span>Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>></span>Back to Home<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">header</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-2xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-2xl font-bold mb-6 text-gray-800"</span>></span>Create New Post<span class="hljs-tag"></<span class="hljs-name">h2</span>></span>
<span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/save"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-4"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>></span>Title<span class="hljs-tag"></<span class="hljs-name">label</span>></span>
<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">required</span>
<span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-6"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>></span>Content<span class="hljs-tag"></<span class="hljs-name">label</span>></span>
<span class="hljs-tag"><<span class="hljs-name">textarea</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">required</span>
<span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>></span><span class="hljs-tag"></<span class="hljs-name">textarea</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-end"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-md"</span>></span>
Save Post
<span class="hljs-tag"></<span class="hljs-name">button</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">form</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
This template allows you to create a new post.
edit.html:
<span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span>
<span class="hljs-tag"><<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">title</span>></span>Edit Post | Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
<span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
<span class="hljs-tag"><<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>></span>Go Blog with MongoDB<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>></span>Back to Home<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">header</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-2xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-2xl font-bold mb-6 text-gray-800"</span>></span>Edit Post<span class="hljs-tag"></<span class="hljs-name">h2</span>></span>
<span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/save"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"id"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"{{.ID.Hex}}"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-4"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>></span>Title<span class="hljs-tag"></<span class="hljs-name">label</span>></span>
<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"{{.Title}}"</span> <span class="hljs-attr">required</span>
<span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-6"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>></span>Content<span class="hljs-tag"></<span class="hljs-name">label</span>></span>
<span class="hljs-tag"><<span class="hljs-name">textarea</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">required</span>
<span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>></span>{{.Content}}<span class="hljs-tag"></<span class="hljs-name">textarea</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-between"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/post/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600 hover:text-gray-800"</span>></span>Cancel<span class="hljs-tag"></<span class="hljs-name">a</span>></span>
<span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-md"</span>></span>
Update Post
<span class="hljs-tag"></<span class="hljs-name">button</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">form</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
This template is used to edit a post.
Create the handlers
Next, set up the handlers to connect with MongoDB and render the templates. Create a new folder called handlers
in your project’s root directory, then add a main.go
file inside it and insert the following code snippet:
<span class="hljs-keyword">package</span> handlers
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"context"</span>
<span class="hljs-string">"log"</span>
<span class="hljs-string">"net/http"</span>
<span class="hljs-string">"time"</span>
<span class="hljs-string">"github.com/gin-gonic/gin"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
<span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
)
<span class="hljs-keyword">type</span> Post <span class="hljs-keyword">struct</span> {
ID primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty" json:"id"`</span>
Title <span class="hljs-keyword">string</span> <span class="hljs-string">`bson:"title" json:"title"`</span>
Content <span class="hljs-keyword">string</span> <span class="hljs-string">`bson:"content" json:"content"`</span>
CreatedAt time.Time <span class="hljs-string">`bson:"created_at" json:"created_at"`</span>
UpdatedAt time.Time <span class="hljs-string">`bson:"updated_at" json:"updated_at"`</span>
}
<span class="hljs-keyword">type</span> Handler <span class="hljs-keyword">struct</span> {
db *mongo.Database
collection *mongo.Collection
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewHandler</span><span class="hljs-params">(db *mongo.Database)</span> *<span class="hljs-title">Handler</span></span> {
<span class="hljs-keyword">return</span> &Handler{
db: db,
collection: db.Collection(<span class="hljs-string">"posts"</span>),
}
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">HomePage</span><span class="hljs-params">(c *gin.Context)</span></span> {
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
cursor, err := h.collection.Find(ctx, bson.M{})
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
<span class="hljs-keyword">return</span>
}
<span class="hljs-keyword">defer</span> cursor.Close(ctx)
<span class="hljs-keyword">var</span> posts []Post
<span class="hljs-keyword">if</span> err = cursor.All(ctx, &posts); err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
<span class="hljs-keyword">return</span>
}
c.HTML(http.StatusOK, <span class="hljs-string">"index.html"</span>, posts)
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">ViewPost</span><span class="hljs-params">(c *gin.Context)</span></span> {
id := c.Param(<span class="hljs-string">"id"</span>)
objID, err := primitive.ObjectIDFromHex(id)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
<span class="hljs-keyword">return</span>
}
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
<span class="hljs-keyword">var</span> post Post
err = h.collection.FindOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID}).Decode(&post)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusNotFound, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Post not found"</span>})
<span class="hljs-keyword">return</span>
}
c.HTML(http.StatusOK, <span class="hljs-string">"post.html"</span>, post)
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">CreatePost</span><span class="hljs-params">(c *gin.Context)</span></span> {
c.HTML(http.StatusOK, <span class="hljs-string">"create.html"</span>, <span class="hljs-literal">nil</span>)
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">EditPost</span><span class="hljs-params">(c *gin.Context)</span></span> {
id := c.Param(<span class="hljs-string">"id"</span>)
objID, err := primitive.ObjectIDFromHex(id)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
<span class="hljs-keyword">return</span>
}
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
<span class="hljs-keyword">var</span> post Post
err = h.collection.FindOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID}).Decode(&post)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusNotFound, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Post not found"</span>})
<span class="hljs-keyword">return</span>
}
c.HTML(http.StatusOK, <span class="hljs-string">"edit.html"</span>, post)
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">SavePost</span><span class="hljs-params">(c *gin.Context)</span></span> {
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
id := c.PostForm(<span class="hljs-string">"id"</span>)
title := c.PostForm(<span class="hljs-string">"title"</span>)
content := c.PostForm(<span class="hljs-string">"content"</span>)
now := time.Now()
<span class="hljs-keyword">if</span> id == <span class="hljs-string">""</span> {
post := Post{
Title: title,
Content: content,
CreatedAt: now,
UpdatedAt: now,
}
result, err := h.collection.InsertOne(ctx, post)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
<span class="hljs-keyword">return</span>
}
log.Printf(<span class="hljs-string">"Created post with ID: %vn"</span>, result.InsertedID)
} <span class="hljs-keyword">else</span> {
objID, err := primitive.ObjectIDFromHex(id)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
<span class="hljs-keyword">return</span>
}
update := bson.M{
<span class="hljs-string">"$set"</span>: bson.M{
<span class="hljs-string">"title"</span>: title,
<span class="hljs-string">"content"</span>: content,
<span class="hljs-string">"updated_at"</span>: now,
},
}
result, err := h.collection.UpdateOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID}, update)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
<span class="hljs-keyword">return</span>
}
log.Printf(<span class="hljs-string">"Updated post with ID: %s (Modified %d documents)n"</span>, id, result.ModifiedCount)
}
c.Redirect(http.StatusSeeOther, <span class="hljs-string">"/"</span>)
}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">DeletePost</span><span class="hljs-params">(c *gin.Context)</span></span> {
id := c.Param(<span class="hljs-string">"id"</span>)
objID, err := primitive.ObjectIDFromHex(id)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
<span class="hljs-keyword">return</span>
}
ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
<span class="hljs-keyword">defer</span> cancel()
result, err := h.collection.DeleteOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID})
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
<span class="hljs-keyword">return</span>
}
log.Printf(<span class="hljs-string">"Deleted %d document(s) with ID: %sn"</span>, result.DeletedCount, id)
c.Redirect(http.StatusSeeOther, <span class="hljs-string">"/"</span>)
}
The code above contains all the logic for managing blog posts. Here’s what each component does:
-
Post struct: Defines the structure of a blog post document with fields for ID, title, content, and timestamps. The
bson
tags specify how fields are stored in MongoDB, whilejson
tags handle JSON serialization. -
Handler struct: Contains a reference to the MongoDB database and the posts collection, providing a centralized way to access the database throughout your handlers.
-
NewHandler function: Creates and initializes a new handler instance with the database connection and sets up the posts collection reference.
-
HomePage: Retrieves all blog posts from the database using
Find()
with an empty filter and renders them using theindex.html
template. -
ViewPost: Fetches a single post by its ObjectID using
FindOne()
and displays it with thepost.html
template. -
CreatePost & EditPost: Render the respective forms for creating new posts or editing existing ones.
-
SavePost: Handles both creating new posts and updating existing ones. It checks if an ID is provided. If not, it creates a new post using
InsertOne()
. Otherwise, it updates the existing post usingUpdateOne()
with MongoDB’s$set
operator. -
DeletePost: Removes a post from the database using
DeleteOne()
and redirects back to the homepage.
Run the application
With everything set up, you can now launch your blog. Open your terminal and run:
go mod tidy && go run main.go
Then, visit http://localhost:8080 in your browser to see your blog in action.
That’s How to Use MongoDB with Go
In this tutorial, you built a simple blog application using Go and MongoDB. You learned how to connect to a MongoDB database using the official Go driver, perform CRUD operations, and render your results with the Gin web framework.
MongoDB’s flexible, document-based structure makes it a great fit for applications where data models need to evolve over time. It allows you to iterate quickly and adapt as your app grows.
As you expand this project, consider adding features such as user authentication, tagging or categorization, comments, pagination, or search functionality to enhance the user experience.
Cheers to building more with Go and MongoDB!
Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & MoreÂ