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.
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
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 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'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 able to insert an entry into MongoDB using the golang driver gopkg.in/mgo.vs and gopkg.in/mgo.vs/bson but I'm not able to pull it out. In the mongo shell, if I do
db.Items.find({ date : 1428762411980 })
it shows me the entry that I just inserted with the Go code. However, if I try to do the following to fetch it in Go, it's telling me that the record isn't found
func fetch(w http.ResponseWriter, r *http.Request){
var result SomeStruct
date := r.FormValue("date")
err := Items.Find(bson.M{"date":date}).One(&result)
...code omitted...
}
func Items() *mgo.Collection {
return DB().C("Items")
}
func DB() *mgo.Database {
return DBSession().DB("mydb")
}
One thing I noticed was that, in the shell, the date is stored as a NumberLong
"date" : NumberLong("1428762411980")
I'm wondering if I have to do something with the date value that I receive from the form in the fetch function before using it to query the database?
Update
Before saving the data to the db, it comes in as a json string like this
"date":1428762411980
I then decode it into a struct
type blah struct{
Id bson.ObjectId `json:"id" bson:"_id"`
Date int64 `json:"date" bson: "date"`
And it gets saved like this (as shown in the shell)
"date" : NumberLong("1428762411980")
r.FormValue returns a string, but you need an int64. Use strconv.ParseInt. Then your query should work.
date, err := strconv.ParseInt(r.FormValue("date"), 10, 64)
// handle err
err = Items.Find(bson.M{"date":date}).One(&result)