Go with MongoDB
June 9, 2021
We created a simple REST API that integrates with a MySQL database in my previous article . We will do the same in this article. But with MongoDB as a NoSQL database.
MongoDB is a cross-platform document-oriented database program. Classified as a NoSQL database. MongoDB uses JSON-like documents with optional schemas.
NoSQL refers to any non-relational database. NoSQL databases can store relationship data. They just store it differently than relational databases do. NoSQL data models allow related data to be nested within a single data structure.
SQL databases use structured query language and have a predefined schema. NoSQL databases have dynamic schemas for unstructured data. SQL databases are table-based, while NoSQL databases are document, key-value, graph, or wide-column stores.
It has a learning curve while working with relational databases because we need to understand SQL. It requires a schema while working with non-relational databases and a client library to integrate it with the programming language. Most NoSQL database systems perform fast, are flexible, are best for unstructured data.
Install
For local development, I suggest you use the Docker image of MongoDB . There is also Mongo Express for data administration.
Go
Let's code with GoLang.
1
2
3
4
5
6
7
import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
First, import these client libraries.
1
2
3
4
5
type article struct {
ID primitive . ObjectID ` bson:"_id" `
Title string ` bson:"Title" `
Content string ` bson:"Content" `
}
Define the struct. The type of ID is primitive.ObjectID. We use bson tag to access data from MongoDB.
1
2
3
4
5
6
7
8
var (
articles [ ] article
client * mongo . Client
collection * mongo . Collection
ctx context . Context
err error
objectID primitive . ObjectID
)
We defined the global variables because we use them in many functions.
Index
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func index ( w http . ResponseWriter , r * http . Request ) {
cur , err := collection . Find ( ctx , bson . D { } )
if err != nil {
log . Fatal ( err )
}
defer cur . Close ( context . TODO ( ) )
for cur . Next ( context . TODO ( ) ) {
var document article
err := cur . Decode ( & document )
if err != nil {
log . Fatal ( err )
}
articles = append ( articles , document )
}
response , err := json . Marshal ( articles )
if err != nil {
log . Fatal ( err )
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
w . Write ( response )
}
Create
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func create ( w http . ResponseWriter , r * http . Request ) {
var request article
err := json . NewDecoder ( r . Body ) . Decode ( & request )
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusBadRequest )
return
}
request . ID = primitive . NewObjectID ( )
insertResult , err := collection . InsertOne ( context . TODO ( ) , request )
if err != nil {
log . Fatal ( err )
}
if insertResult . InsertedID != nil {
response , err := json . Marshal ( article { request . ID , request . Title , request . Content } )
if err != nil {
log . Fatal ( err )
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
w . Write ( response )
}
}
Read
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func read ( w http . ResponseWriter , r * http . Request , key string ) {
objectID , err = primitive . ObjectIDFromHex ( key )
if err != nil {
log . Fatal ( err )
}
filter := bson . D { { Key : "_id" , Value : objectID } }
var document article
err = collection . FindOne ( ctx , filter ) . Decode ( & document )
if err != nil {
http . Error ( w , http . StatusText ( http . StatusNotFound ) , http . StatusNotFound )
return
}
response , err := json . Marshal ( document )
if err != nil {
log . Fatal ( err )
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
w . Write ( response )
}
Update
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func update ( w http . ResponseWriter , r * http . Request , key string ) {
objectID , err = primitive . ObjectIDFromHex ( key )
if err != nil {
log . Fatal ( err )
}
var request article
err := json . NewDecoder ( r . Body ) . Decode ( & request )
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusBadRequest )
return
}
request . ID = objectID
filter := bson . D { { Key : "_id" , Value : objectID } }
update := bson . D {
{ Key : "$set" , Value : bson . D {
{ Key : "Title" , Value : request . Title } ,
{ Key : "Content" , Value : request . Content } ,
} } ,
}
updateResult , err := collection . UpdateOne ( ctx , filter , update )
if err != nil {
log . Fatal ( err )
}
if updateResult . MatchedCount != 0 {
response , err := json . Marshal ( request )
if err != nil {
log . Fatal ( err )
}
w . Header ( ) . Set ( "Content-Type" , "application/json" )
w . Write ( response )
}
}
Delete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func delete ( w http . ResponseWriter , r * http . Request , key string ) {
objectID , err = primitive . ObjectIDFromHex ( key )
if err != nil {
log . Fatal ( err )
}
filter := bson . D { { Key : "_id" , Value : objectID } }
deleteResult , err := collection . DeleteOne ( ctx , filter )
if err != nil {
log . Fatal ( err )
}
if deleteResult . DeletedCount != 1 {
http . Error ( w , http . StatusText ( http . StatusBadRequest ) , http . StatusBadRequest )
}
}
Closing
We created the same CRUD functions as we did to the version of MySQL. The difference is these are for MongoDB. There is no SQL syntax here.
We use bson.D{} as a document to find, filter, and update. We use primitive.NewObjectID() to create a new ID and primitive.ObjectIDFromHex() to read the ID.
You can get the source code on https://github.com/aristorinjuang/go-databases/tree/master/04_mongodb . I also provide dummy data that you may import to your MongoDB.
References
Related Articles
Comments
Please enable JavaScript to view the comments powered by Disqus.