I have Go code that connects to a mongodb database.
The problem is that when I'm trying to get a record from the collection there is an "_id" field of the ObjectId type, but in the mgo driver ObjectId is
type ObjectID [12]byte
but when I'm trying to get record Go says:
reflect.Set: value of type []uint8 is not assignable to type ObjectID
I have tried to create my own []uint8 type but I have no idea how to convert []uint8 ("ObjectId") to string or to find some record by those ids.
// ObjectId type that mongodb wants to see
type ObjectID []uint8
// model
type Edge struct {
ID ObjectID `bson:"_id"`
Name string `bson:"name"`
StartVertex string `bson:"startVertex"`
EndVertex string `bson:"endVertex"`
}
// method for getting record by those id
session, err := mgo.Dial(config.DatabaseURL)
if err != nil {
fmt.Printf("Error is: %s", err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
//edges collection
e := session.DB(config.DatabaseName).C(config.EdgesCollection)
var result models.Edge
err = e.Find(bson.M{"_id": fmt.Sprintln("ObjectId('", id, "')")}).One(&result)
if err != nil {
fmt.Println("Error is: ", err)
}
You have to use the "predefined" bson.ObjectId to model values of MongoDB's ObjectId:
type Edge struct {
ID bson.ObjectId `bson:"_id"`
Name string `bson:"name"`
StartVertex string `bson:"startVertex"`
EndVertex string `bson:"endVertex"`
}
And when you query an object by ID whose type is MongoDB's ObjectId, use a value of type bson.ObjectId. And you may use the Collection.FindId() method:
var id bson.ObjectId = ...
err = e.FindId(id).One(&result)
See details here: Find by id with mgo; and MongoDB slice query into golang
Related
I just started learning GORM and currently trying to fetch data from one to many tables.
I have two tables :users and documents. A user can have multiple documents . When i try fetching documents I keep getting the error
documents: unsupported relations for schema User
SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL
Below is the code where I attempt to fetch data
type User struct {
gorm.Model
Name string
Email string
Password string
Documents []Document
}
type Document struct {
gorm.Model
Name string
DateCreated string
UserID uint
}
Function to fetch data
func GetAll(db *gorm.DB) ([]models.User, error) {
var users []models.User
// err := db.Model(&models.User{}).Preload("documents").Find(&users).Error
err:=db.Preload("documents").Find(&[]models.User{}).Error
fmt.Println(err)
fmt.Println("got users")
return users, err
}
What am I doing wrong here?
db.Preload("documents") should be db.Preload("Documents")
same as name of the field Documents in User struct
Getting this error while binding mongodb document to GO Struct using docstore collection iterator.
Database: Azure CosmosDB mongoDb API
Go Driver: Docstore
Code details:
Cosmos DB Constructors Code
client, err := c.newClient(ctx, true)
if err != nil {
log.Error("error connecting to mongodb cluster", zap.Error(err))
return nil, err
}
database := client.Database(c.dbName)
collection := database.Collection(c.collName)
return mongodocstore.OpenCollection(collection, "", nil)
Go struct for mapping with Mongo Db document
type utterance struct {
ID primitive.ObjectID `docstore:"_id,omitempty"`
User string `docstore:"user,omitempty"`
Locale string `docstore:"Locale,omitempty"`
Text string `docstore:"Text,omitempty"`
Source string `docstore:"Source,omitempty"`
Timestamp time.Time `docstore:"Timestamp,omitempty"`
DocstoreRevision interface{}
}
MondoDb Document
{
"_id" : ObjectId("60d5e18539864e948a8851a6"),
"User" : "auth0|6049b5ef5d79540071db6a0a",
"Locale" : "en_US",
"Text" : "Hi",
"Source" : "UTTERANCE_SOURCE_USER",
"Timestamp" : {
"$date" : 1624629637002
},
"DocstoreRevision" : "bf3b35d8-54ed-4a23-a08f-7d41b5c34085"
}
Method to call the docstore collection and iterate
i := s.collection.Query().Get(ctx)
defer i.Stop()
var results []*services.Utterance
for {
fmt.Println("for every document: ")
//var native utterance
doc := &utterance{}
err := i.Next(ctx, doc) //error at this line
if err == io.EOF {
break
} else if err != nil {
fmt.Println(“getting to this err block“)
return nil, err
}
u := doc.ToProto()
results = append(results, u)
}
Try setting the ID to a pointer type:
type utterance struct {
ID *primitive.ObjectID `docstore:"_id,omitempty"`
User string `docstore:"user,omitempty"`
Locale string `docstore:"Locale,omitempty"`
Text string `docstore:"Text,omitempty"`
Source string `docstore:"Source,omitempty"`
Timestamp time.Time `docstore:"Timestamp,omitempty"`
DocstoreRevision interface{}
}
Probably when you create the struct to be decoded the primitive.ObjectID is being initialized and the driver don't know to decode it.
And be careful. The docstore is a generic Document driver. It is not specific for MongoDB. So it probably don't work well with MongoDB specific types.
Reading the driver for mongodb https://pkg.go.dev/gocloud.dev/docstore/mongodocstore
There is a way to set what is stored in the _id field. I understand docstore don't know how to decode ObjectID from MongoDB.
How do I set TTL indexes in a document using "mongo-go-driver"?
suppose here is my document model:
type Session struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
AccessToken string `json:"access_token" bson:"access_token"`
ExpireOn int64 `json:"expire_on" bson:"expire_on"`
}
and here I am inserting new document:
sessionCollection := database.Collection(COLLECTION_SESSION)
_, err = sessionCollection.InsertOne(context.TODO(), s)
if err != nil {
responses.RespondWithERROR(w, http.StatusInternalServerError, err)
return
}
Now I want that this session will be removed after a few times.
I found the way to do that in documentation Expire Data from Collections by Setting TTL but can't figure out How to do the same thing in go using mongo-go-driver.
Trying to use mongo go driver to decode a fetch a single user document and decode it into a struct, using the findOne method. But, I am unable to decode the document ID on the struct field. I tried looking for it in their examples, or at other sites/blogs, but no luck. I am working with:
go v1.13.4
mongo v4.2.1
mongo-go-driver v1.1.3
Below is the code snippet:
type User struct {
ID interface{} `json:"_id"`
Name string
Email string
Password string // hashed
}
/* Other versions of User struct which I already tried
type User struct {
ID interface{}
Name string
Email string
Password string // hashed
}
type User struct {
ID string `json:"_id"`
Name string
Email string
Password string // hashed
}
type User struct {
ID string
Name string
Email string
Password string // hashed
}
*/
func main() {
conn := service.MongoConn() // get a mongo connection on the required database
user := &service.User{}
err := conn.Collection("users").
FindOne(context.Background(), bson.M{"email": "foo#bar.com"}).
Decode(user)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", user)
}
I want to use doc ID as a reference in other documents in a different collection, otherwise, I have to resort to some other unique field like email.
the struct should be like this:
import "go.mongodb.org/mongo-driver/bson/primitive"
type User struct {
ID primitive.ObjectID `bson:"_id"`
...
}
to transfer your _id to string please use xx.ID.Hex()
see more on Github
I have the following struct
type Account struct {
ID primitive.ObjectID `json:"id" bson:"_id"`
Email string `json:"email"`
Password string `json:"password"`
}
and the following function
func (a *Account) Create() map[string]interface{} {
if resp, ok := a.Validate(); !ok {
return resp
}
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(a.Password), bcrypt.DefaultCost)
a.Password = string(hashedPassword)
users := db.Collection("users")
insertResult, err := users.InsertOne(context.TODO(), a)
if err != nil {
return utils.Message(false, "Error inserting user document "+err.Error())
}
... more code down hre
}
The problem I am having is that I can insert the first account, but any account after that can't be inserted due to a dup key error on the _id field. I know that mongoDB will auto generate an _id field and will use the one provided if there is an id. In my case in this create function, the a.ID (_id) is always be NilValue "_id" : ObjectId("000000000000000000000000")
Is there any way mongoDB can generate an _id for me even if I provide and ID field with the nil value?
I need the Account.ID `bson: "_id"` property on there so I can decode it when I am reading from mongoDB such as
func GetUser(email string) *Account {
account := &Account{}
users := db.Collection("users")
filter := bson.D{{"email", email}}
if err := users.FindOne(context.TODO(), filter).Decode(&account); err != nil {
return utils.Message(false, "Error Retrieving account for "+email)
}
// account.ID will be available due to the bson tag
}
I'd appreciate some feedback if I am doing this wrong and how I could do this better.
Thanks!
I found the problem. I did not add ```omitempty` to the bson tag.
It should be
type Account struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Email string `json:"email"`
Password string `json:"password"`
}