I am using grpc+golang+mongodb, and I have the following proto file.
enum InventoryType {
LARGE = 0;
SMALL = 1;
}
my go code:
import (
"context"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"inventory-service/pb"
)
func (i *Inventory) CreateInventory(ctx context.Context, req *pb.CreateInventoryRequest) (*pb.CreateInventoryResponse, error) {
inventory := req.GetInventory()
data := pb.Inventory{
Inventory: inventory.GetInventory(),
}
mctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
client, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
collection := client.Database("test_db").Collection("test_collection")
collection.InsertOne(mctx, data)
return &pb.CreateInventoryResponse{}, nil
}
and when I save the enum to mongodb using golang, it saves the int value 0, 1 instead of 'LARGE', 'SMALL', any ideas on how I can save string instead?
Protobuf is for communication, not for database modeling. You shouldn't use protobuf generated files to save in your database.
Instead create a separate type that models the document you want to store in the database, in which you may store the string representation of your enum, and that will get stored in the database.
For example:
type MyData {
Inventory string `bson:"inventory"`
}
And using it:
data := MyData{
Inventory: inventory.GetInventory().String(),
}
Related
I am creating simple REST API using MongoDB and golang as a driver.
I was able to create POST request which can be found here:
terminal output.
However, when creating GET request, i always need to get it by bson _id. Would someone be able to let me know how to retrieve from json id not bson _id from golang script. If this is not possible, I would appreciate if someone let me know how to convert id to _id.
models/user.go
package models
import (
"gopkg.in/mgo.v2/bson"
)
type User struct {
Id bson.ObjectId `json:"id" bson: "_id"`
Name string `json:"name" bson: "name"`
Gender string `json:"gender" bson: "gender"`
Age int `json:"age" bson: "age"`
}
controllers/user.go file
type UserController struct {
session *mgo.Session}
func httpResponse(w http.ResponseWriter, jsonOut []byte, code int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
fmt.Fprintf(w, "%s", jsonOut)
}
func NewUserCOntroller(s *mgo.Session) *UserController {
// return the address of UserController
return &UserController{s}
}
func (uc UserController) GetUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
id := p.ByName("id")
if !bson.IsObjectIdHex(id) {
w.WriteHeader(http.StatusNotFound)
}
// oid is something you use in mongo
oid := bson.ObjectIdHex(id)
u := models.User{}
if err := uc.session.DB("mongolang").C("users").FindId(oid).One(&u); err != nil {
w.WriteHeader(404)
return
}
uj, err := json.Marshal(u)
if err != nil {
fmt.Println(err)
}
httpResponse(w, uj, http.StatusOK)
}
func (uc UserController) CreateUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
// its empty for now
u := models.User{}
json.NewDecoder(r.Body).Decode(&u)
u.Id = bson.NewObjectId()
uc.session.DB("mongolang").C("users").Insert(u)
jsonOut, _ := json.Marshal(u)
httpResponse(w, jsonOut, http.StatusOK)
fmt.Println("Response:", string(jsonOut), " 201 OK")
}
main.go
package main
import (
"net/http"
"github.com/julienschmidt/httprouter"
"gopkg.in/mgo.v2"
"mongo-golang/controllers"
)
func main() {
// create new instance
r := httprouter.New()
// new session
uc := controllers.NewUserCOntroller(getSession())
r.GET("/user/:id", uc.GetUser)
r.POST("/user", uc.CreateUser)
r.DELETE("/user/:id", uc.DeleteUser)
http.ListenAndServe("localhost:9000", r)
}
func getSession() *mgo.Session {
// get session and connect with mongo
s, err := mgo.Dial("mongodb://localhost")
if err != nil {
panic(err)
}
return s
}
Would someone be able to let me know how to retrieve from json id not bson _id from golang script.
You can do that only if you save bson Id as a Hex string in the additional field in an object, but don't do that. That is unnecessary and you won't get anything.
If this is not possible, I would appreciate if someone let me know how to convert id to _id.
There are two functions that converting bson ObjectID to string and string to bson ObjectID
for id to _id, you already use that function in your code:
oid := bson.ObjectIdHex(id)
bson.ObjectIdHex() convert hex representation of objectID to bson.objectID. Hex representation is what you would see in JSON output.
After you invoke that function you get bson.ObjetID. There is a method .Hex() that can get you Hex (text/json) representation of that object.
oid := bson.ObjectIdHex(id)
json_represenation_of_bson_object_id = oid.Hex()
Also, you use the old mongo driver, a new driver written and maintained by MongoDB is what you should use:
https://github.com/mongodb/mongo-go-driver
I have a document in mongodb in this format,
{
field1: string,
field2: float64,
field3: {...float64}
}
Ultimately I would like to always get field1 & field2 and pick/choose from the field3 object.
To do it, I decode the data into a struct like this,
type MongoScore struct {
field1 string `json:"field1"`
field2 float64 `json:"field2"`
field3 map[string]float64 `json:"field3"`
}
The part I am wondering is whether there is a more efficient approach to pull this data with different types.
Assuming you have the following data struct:
type Product struct {
ID primitive.ObjectID `bson:"_id"`
Title string `bson:"product"`
Description string `bson:"description"`
count int64 // <- this is not exported, so data won't be filled
}
In Golang, Only exported fields or methods are accessible from outside it's package.
Use struct field tags to tell Mongodb load the data from collection straight to the matched fields. Here mongodb matches bson tag with fields in collection.
func main() {
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
client, err = mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017/"))
if err != nil {
log.Fatalf("can't connect to database: %v\n", err)
}
objID, _ := primitive.ObjectIDFromHex("619dd79acad38082f9ce16af")
db := client.Database("db")
col := db.Collection("products")
filter := bson.D{
{"_id", objID},
}
dest := &Project{}
err := col.FindOne(ctx, filter).Decode(dest)
if err != nil {
log.Fatalln(err)
}
The method Decode Unmarshals found data into dest.
I'm trying to learn Go API development. I have a MongoDB instance running in a Docker container. I'm trying to follow a few guides but am failing on simple queries. I don't fully understand the use of BSON and JSON tags here. I do know what those terms mean. So here is my code.
import (
"fmt"
"time"
"gopkg.in/mgo.v2/bson"
)
const (
hosts = "localhost:27017"
database = "my_database"
username = "dev1"
password = "password123"
collection = "users"
)
type users struct {
user string `bson:"user" json:"user"`
data string
}
func main() {
fmt.Println("Starting Application!")
info := &mgo.DialInfo{
Addrs: []string{hosts},
Timeout: 60 * time.Second,
Database: database,
Username: username,
Password: password,
}
session, err1 := mgo.DialWithInfo(info)
if err1 != nil {
panic(err1)
}
defer session.Close()
col := session.DB(database).C(collection)
var user users
var books []users
var username = "cat"
col.Insert(&users{user: "dog", data: "blah"})
err3 := col.Find(bson.M{"user": username}).One(&user)
fmt.Println(user)
fmt.Println(err3)
count, err2 := col.Count()
if err2 != nil {
panic(err2)
}
fmt.Println(fmt.Sprintf("Messages count: %d", count))
fmt.Println(user)
col.Find(bson.M{}).All(&books)
fmt.Println(books)
}
Basically I'm getting empty objects on the print line but am getting the correct Message count. I inserted the objects with robomongo if that helps.
You must export fields of structs, else they are ignored by the mgo package. Change fields of users to User and Data.
type users struct {
User string `bson:"user" json:"user"`
Data string `bson:"data" json:"data"`
}
By default when a struct value is transformed / stored / retrieved from MongoDB, the field name is used. If you want to use different names, you may use tags to tell what names should the fields map to.
I'm trying to learn Go API development. I have a MongoDB instance running in a Docker container. I'm trying to follow a few guides but am failing on simple queries. I don't fully understand the use of BSON and JSON tags here. I do know what those terms mean. So here is my code.
import (
"fmt"
"time"
"gopkg.in/mgo.v2/bson"
)
const (
hosts = "localhost:27017"
database = "my_database"
username = "dev1"
password = "password123"
collection = "users"
)
type users struct {
user string `bson:"user" json:"user"`
data string
}
func main() {
fmt.Println("Starting Application!")
info := &mgo.DialInfo{
Addrs: []string{hosts},
Timeout: 60 * time.Second,
Database: database,
Username: username,
Password: password,
}
session, err1 := mgo.DialWithInfo(info)
if err1 != nil {
panic(err1)
}
defer session.Close()
col := session.DB(database).C(collection)
var user users
var books []users
var username = "cat"
col.Insert(&users{user: "dog", data: "blah"})
err3 := col.Find(bson.M{"user": username}).One(&user)
fmt.Println(user)
fmt.Println(err3)
count, err2 := col.Count()
if err2 != nil {
panic(err2)
}
fmt.Println(fmt.Sprintf("Messages count: %d", count))
fmt.Println(user)
col.Find(bson.M{}).All(&books)
fmt.Println(books)
}
Basically I'm getting empty objects on the print line but am getting the correct Message count. I inserted the objects with robomongo if that helps.
You must export fields of structs, else they are ignored by the mgo package. Change fields of users to User and Data.
type users struct {
User string `bson:"user" json:"user"`
Data string `bson:"data" json:"data"`
}
By default when a struct value is transformed / stored / retrieved from MongoDB, the field name is used. If you want to use different names, you may use tags to tell what names should the fields map to.
I was wondering if there is any way to have a stuct field that doesn't get commited to mgo even if it isn't empty.
The only way I have found to do this is to make the field lowercase, which makes it a pain to access. Is there another way?
This is an example, and my goal here is to not commit the SSN into the database but still have it uppercase.
package main
import (
"fmt"
"crypto/sha1"
"encoding/base64"
"labix.org/v2/mgo"
)
type Person struct{
Name string
SSN string
HashedSSN string
}
func main() {
bob := Person{"Bob", "fake_ssn", ""}
hasher := sha1.New()
hasher.Write( []byte(bob.SSN))
sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
bob.HashedSSN = sha
mgoSession, err := mgo.Dial("localhost:27017")
if err != nil {
fmt.Println("mongo_config#initMongoSessions : Could not dial to mgoSession", err)
} else {
mgoSession.DB("test").C("person").Insert(bob)
}
}
Thanks,
You can do that by using the field tag as follows:
type T struct {
Field string `bson:"-"`
}