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
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
I'm trying to fetch one to many table data from my postgres DB using GORM but I keep getting the following error when I attempt to print the returned data
&{0xc00015e3f0 <nil> 1 0xc000272e00 0}
I have verified that the data exists in my db and here is the code showing how I've structured everything
type User struct {
gorm.Model
Name string
Email string
Password string
Documents []Document
}
type Document struct {
gorm.Model
Name string
DateCreated string
UserID uint
}
func GetAll(db *gorm.DB) ([]*models.User,) {
var users []*models.User
//err := db.Model(&models.User{}).Preload("Documents").Find(&users).Error
results:=db.Preload("Documents").Find(&users)
fmt.Println(results)
fmt.Println("got users")
return users
}
func main (){
models.Db.Create(&models.User{Name: "Ellie",Email: "Ellie#lous",
Documents: []models.Document{{Name:"Ellies ID",},{Name: "Ellies Guitar "}},
})
GetAll(models.Db)
}
Your error is that the data from your query will scan into users, not results.
Try this:
_ = db.Preload("Documents").Find(&users)
for _, user := range users {
fmt.Println(user)
}
The Find function returns a *gorm.DB object, not the results of your query.
I have a User struct like this:
type User struct {
Username string `json:"username" bson:"username"`
AuthorizationKey string `json:"authorization_key" bson:"authorization_key"`
IsActive bool `json:"is_active" bson:"is_active"`
}
Right now I can query for the whole username using
user := &User{}
if err := db.Where(&User{
Username: username,
}).Find(&user).Error; err != nil {
return user, err
}
And I use this statement for like query (plain query)
db.Where("username LIKE ?", fmt.Sprintf("%%%s%%", username)).Find(&users)
Is it possible to use like query for username field with struct format? How about greater than or less than?
I think it's not possible, Struct in where condition used for equal check for field (Ref)
db.Where(&User{ Username: username})
For Like/gte/lte query you have to use plain SQL inside where()
db.Where("username LIKE ?", fmt.Sprintf("%%%s%%", username)).Find(&users)
Reference here
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
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"`
}