"Has many" relation giving empty result - go

I am trying to define one to many relation with gorm ORM . I have read all the docs over and over again . Could not find a way to do it.
func GetUser1(c *gin.Context) {
var user models.User
var activities models.UserActivity
query := DB.Debug().Find(&user, 1).Model(&user).Related(&activities).Error
if query != nil {
panic(query)
}
c.JSON(200, &user)
}
My Models are ..
type User struct {
Id int64
Username string
Password string `json:"-"`
Email string `json:",omitempty"`
UserActivities []UserActivity
}
type UserActivity struct {
Id int64
UserId int64 `json:"-"`
ActorId int64
CreatedAt time.Time
}
Debug Results are
[2015-11-21 22:21:54] [3.17ms] SELECT * FROM `users` WHERE (`id` = '1')
[2015-11-21 22:21:54] [1.39ms] SELECT * FROM `user_activities` WHERE (`user_id` = '1')
But I am getting null results
{
"Id": 1,
"Username": "test1",
"Email": "test1#friesen.com",
"UserActivities": null
}
All the primary keys and Indexes are right . I have also tried puttin gorm:"primary_key" and sql:"index" in UserActivities no luck so far .
However if I replace UserActivities []UserActivity with UserActivities UserActivity then i get only one row which seems to be right but why UserActivities []UserActivity giving no results

use gorm built in model gorm.Model so that your not messing up the "ID" constant

The solution to your problem is very simple.
Rather than querying
var user models.User
var activities models.UserActivity
query := DB.Debug().Find(&user, 1).Model(&user).Related(&activities).Error
just query
var user models.User
query := DB.Debug().Find(&user, 1).Model(&user).Related(&user.UserActivities).Error

Related

Unable to scan type of uuid.UUID into UUID in sqlmock Golang

I have the following test function.
func (s *Suite) Test_delete() {
var (
id = uuid.New()
name = "test"
quantity = 2
)
s.mock.ExpectQuery(regexp.QuoteMeta(
`SELECT * FROM "items" WHERE code = $1 AND "items"."deleted_at" IS NULL`,
)).
WithArgs(id).
WillReturnRows(sqlmock.NewRows([]string{"code", "name", "quantity"}).
AddRow(id, name, quantity))
err := s.repository.DeleteItem(id.String())
require.NoError(s.T(), err)
}
Now the problem is trying to scan the id variable into the row for the column code. In my Product struct, I have code defined as follows.
type Item struct {
Code uuid.UUID `gorm:"type:uuid;primaryKey" json:"code"`
Name string `json:"name" validate:"required"`
Quantity int `json:"qty" validate:"required,min=0"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
}
func (i *Item) BeforeCreate(tx *gorm.DB) (err error) {
if i.Code == uuid.Nil {
i.Code = uuid.New()
}
return
}
Now the problem is when I try to run the test function, it is somehow unable to scan uuid.UUID into UUID even though they are both the same types. Here is the exact error message.
msql: Scan error on column index 0, name "code": Scan: unable to scan type uuid.UUID into UUID
Could someone help me on this part?
Read this. I assume there is type casting error. Changing WillReturnRows(sqlmock.NewRows([]string{"code", "name", "quantity"}).AddRow(id, name, quantity))->WillReturnRows(sqlmock.NewRows([]string{"code", "name", "quantity"}).AddRow(id.String(), name, quantity)) may help.

How can i build a subquery in a gorm belongs-to relationship?

I am using GORM in go for mysql queries. I have the following structs
type Patient struct {
gorm.Model
}
type ClinicalTrialPatient struct {
gorm.Model
PatientID uint
Patient Patient
}
I would like go generate a SQL Statement like
SELECT * FROM `clinical_trial_patients` WHERE patient_id IN (SELECT ID FROM Patients WHERE pvs_pat_id = '1' AND DELETED_AT is null) AND `clinical_trial_patients`.`deleted_at` IS NULL
Unfortunately I dont get it how i can generate a statement like this. I was trying something like this:
result := orm.Where(&ClinicalTrialPatient{
Patient: Patient{
PvsPatId: "1",
},
}).Find(&trialPatients)
But the following statement was generated
SELECT * FROM `clinical_trial_patients` WHERE `clinical_trial_patients`.`deleted_at` IS NULL
You can use Preload to do belongs-to relationship.
type Patient struct {
gorm.Model
ClinicalTrialPatients []ClinicalTrialPatient // add this field
}
type ClinicalTrialPatient struct {
gorm.Model
PatientID uint
Patient Patient
}
...
var result Patient
err := orm.Preload("ClinicalTrialPatients").First(&result, 1).Error
if err != nil {
panic(err)
}
fmt.Println(result.ClinicalTrialPatients)
...
Or based on your question, you can use sub-query like this:
pvsPatId := "1"
err := orm.
Where(
"patient_id in (?)",
db.Table("Patients").
Select("id").
Where("pvs_pat_id = ?", pvsPatId),
).
Find(&trialPatients).Error
if err != nil {
panic(err)
}

"doesn't have relation" from go-pg

I am trying to pull data for CountyEntity that related with CityEntity:
type CityEntity struct {
tableName struct{} `pg:"city,alias:ci,discard_unknown_columns"`
Id string `pg:"id"`
Name string `pg:"name"`
}
type CountyEntity struct {
tableName struct{} `pg:"county,alias:co,discard_unknown_columns"`
Id int64 `pg:"id"`
Name string `pg:"name"`
DefaultTargetXDockId int64 `pg:"defaulttargetxdockid"`
MapsPreference string `pg:"mapspreference"`
EmptyDistrictAllowed bool `pg:"empty_district_allowed"`
CityId int64 `pg:"cityid"`
City *CityEntity `pg:"fk:cityid"`
}
My query is:
db, _ := repository.pgRepository.CreateDBConnection(.....)
var counties []model.CountyEntity
err := db.Model(&counties).
Join("inner join test.city ci on ci.id = co.cityid").
Relation("City").
Where("co.cityid = ?", cityId).
Select()
return counties, err
it throws that:
model=CountyEntity does not have relation="City"
But actually, I have the relation between city and county table on the database.
Db Relation Image
I tried different ways to solve but I couldn't solve it. Does anybody have an idea about what is the root cause of it and what is the possible solutions?
Pretty old and I'm sure you've figured it out by now, but for anyone else that stumbles across this your model should look like this
type CountyEntity struct {
tableName struct{} `pg:"county,alias:co,discard_unknown_columns"`
Id int64 `pg:"id"`
Name string `pg:"name"`
DefaultTargetXDockId int64 `pg:"defaulttargetxdockid"`
MapsPreference string `pg:"mapspreference"`
EmptyDistrictAllowed bool `pg:"empty_district_allowed"`
CityId int64 `pg:"cityid"`
City *CityEntity `pg:"rel:has-one,fk:cityid"`
}
Notice the "rel:has-one" added to the city column. You can find more information about all of these here: https://pg.uptrace.dev/models/

Designing a Datastore schema for a page that users can edit (e.g. a wikipedia/stackoverflow page)

The idea is to design a table/entity that contains some basic info, as well as a Markdown-Content field that would allow users to easily create tables and such.
I'm thinking something like this:
type Tournament struct {
ID in64 `datastore:"-"`
MDContent []byte `datastore:",noindex"`
Name string
URL string
DateCreated int64
CreatedBy string
DateUpdated int64
UpdatedBy string
ApprovalStatus int64 // 0=to be decided, 1=approved, 2=rejected, 3=discontinued
ApprovalBy string
}
My problem is figuring out how to update it. The ID field will also be used as the URL path, e.g. if an entity has ID 7 then it will be displayed on example.com/tournament/7.
I believe this eliminates the possibility of simply creating a new entity with updated data, and then set the ApprovalStatus=3 on the previous entity, because if you do as such then the example.com/tournament/7 URL will no longer request the correct ID.
I also don't like the idea of creating my own unique ID because I think it would be great to simply take advantage of the Datastore ID generation (which also makes it easy to get the correct entity based on URL); I considered creating a new entity/table that would keep track of revisions but I'm not sure how efficient all of this is, so I was hoping some expert might be able to give some advice.
Update related to #mkopriva solution:
If you do it this way, then it's necessary to include a TournamentID field inside the TournamentEdit entity struct I think?
type TournamentEdit struct {
ID in64 `datastore:"-"`
TournamentID int64
MDContent []byte `datastore:",noindex"`
DateCreated int64
CreatedBy string
ApprovalStatus int64 // 0=to be decided, 1=approved, 2=rejected, 3=discontinued
ApprovalBy string
}
And then the retrieve function could look like this:
func (db *datastoreDB) GetTournamentByKeyID(ctx context.Context, keyID int64) (*Tournament, error) {
key := datastore.IDKey("Tournament", keyID, nil)
var tournamnet Tournament
err := db.client.Get(ctx, key, &tournament)
// err checking
tournament.ID = key.ID
var edits TournamentEdits
query := datastore.NewQuery("TournamentEdit")
query = query.Filter("TournamentID =", tournament.ID)
query = query.Filter("ApprovalStatus =", 1)
if _, err := db.client.GetAll(ctx, query, &edits); err != nil {
//err checking
}
tournament.Edits = edits // I guess this is wrong way to do it?
return &tournament, nil
}
Would this work?
One thing you could do is to simply create a new entity that would represent the edit of a tournament. By the way, I'm not a datastore user so I'm not sure if this is how you would model the entities but the general idea is the same for most, if not all, databases:
type Tournament struct {
ID in64 `datastore:"-"`
MDContent []byte `datastore:",noindex"`
Name string
URL string
DateCreated int64
CreatedBy string
DateUpdated int64
UpdatedBy string
Edits []TournamentEdit
}
type TournamentEdit struct {
ID in64 `datastore:"-"`
MDContent []byte `datastore:",noindex"`
DateCreated int64
CreatedBy string
ApprovalStatus int64 // 0=to be decided, 1=approved, 2=rejected, 3=discontinued
ApprovalBy string
}
This should allow you to have multiple edits from different users in the queue, CRUD a specific edit, and or filter edits by their status.

How to dereference dbref in mgo?

var (
type User struct{
Id bson.ObjectId `bson:"_id"`
Name string
}
type Post struct{
Id bson.ObjectId `bson:"_id"`
Uid string
User User
ref mgo.DBRef
Title string
}
)
//try 10000 times inserts
id := bson.NewObjectId()
user := &User{ id, "test"}
db.C("users").insert(user)
post := db.C("Post").insert(&Post{Uid: id.hex(), ref: mgo.DBRef{"ref":"users", "id": id}, Title:"test dbref"})
//first way so dirty -_-!
//mysql: left join users on user.id=post.uid, how to do in mgo ?
posts := new([]User)
db.C("posts").Find(nil).All(posts)
ids := []bson.ObjectId
for _, p := range posts{
ids = append(ids, p.Uid)
}
users := make([]User, len(ids))
db.C("users").Find(bson.M{"_id": {"$in": ids}}).All(users)
//and then set the User attribute?
for _,u := range users {
for _, m := range m{
if m.Uid == u.Id {
m.User = m
}
}
}
secondary way,with ref attribute, but mgo.session will try to findid
for _,m := range posts{
db.FindRef(m.ref).One(&m.User)
}
//3th way, with mapReduce ??
it's my first golang + mongodb, so what is the best way to archive dbref or joins?
Thx
Instead of using DBRef, you can just use manual reference method for connecting two or more related documents. For example your struct can just look as below:
type User struct{
Id bson.ObjectId `bson:"_id"`
Name string `json:"name"`
}
type Post struct{
UserId bson.ObjectId `json:"userid"` // manual ref to User
Title string
}
You can then use $lookup aggregation stage to perform a left outer join. For example, to find out all posts based on users:
pipeline := []bson.M{
bson.M{"$lookup": bson.M{
"from": "posts",
"foreignField":"userid",
"localField":"_id",
"as":"posts",
},
},
}
result := []bson.M{}
err := coll_users.Pipe(pipeline).All(&result)
Example result:
{
"_id": ObjectId("590ab726f4bab950360c2dbe"),
"name": "test",
"posts": [
{
"_id": ObjectId("590ab72619663bad7743ff9e"),
"userid": ObjectId("590ab726f4bab950360c2dbe"),
"title": "test manual reference"
}
]
}
Alternative to storing users and posts in separate collections, you could also embed/sub-document. See also Data Modelling

Resources