Is there a way (besides using raw SQL) to implement an insert in gorm with a subquery?
I have the following definitions
type Customer struct {
ID string
Name string
OwnerID string
...
}
type PaymentMethod struct {
ID string
CustomerID // references Customer.ID
Vendor string
Month int
Year int
...
}
I want to find a customer by OwnerID and then to insert a payment method for that user.
If I were to use raw SQL, I would write something along the lines of:
INSERT INTO payment_method (ID, CustomerID, Month, Year)
SELECT (ID, 12, 2022)
FROM customer
WHERE owner_id = <some_value>
Is there a way to implement it in GORM in a single query?
Check the below code snippet.
I used row expressions to get the customer id by owner id.
selectID := clause.Expr{
SQL: "(SELECT id FROM customer WHERE owner_id = ?)",
Vars: []interface{}{
1, // Owner id
},
}
values := map[string]interface{}{
"customer_id": selectID,
"month": 12,
"year": 2022,
"created_at": time.Now(),
"updated_at": time.Now(),
}
err = db.Table("payment_method").Create(values).Error
if err != nil {
fmt.Printf("%s", err)
}
Following models were used.
type Customer struct {
gorm.Model
Name string
OwnerID string
}
type PaymentMethod struct {
gorm.Model
Vendor string
CustomerID int
Month int
Year int
}
Related
so I have a database which 3 tables: creditor, debtor and operation, the operation are refer to a creditor and a debtor if this debtor is already in the table I dont want that create a new row, the same for debtor, but the operation have to be storage with the id of the already in database debtor or/and creditor.
So for try to make this I put the uniqueIndex:idx_name which only storage the data if both (name/bic or name/iban) are unique, so that its good, but the problem is gorm give this error and doesnt storage the operation.
Error 1452: Cannot add or update a child row: a foreign key constraint fails (`mybb`.`operations`, CONSTRAINT `fk_operations_creditor` FOREIGN KEY (`creditor_id`) REFERENCES `creditors` (`id`))
Is there any way to do this? or do I have to separately check if the debtor and creditor exist, save it if not or get the id if yes and later save the operation?.
Structures
type Creditor struct {
gorm.Model
Name string `json:"name" gorm:"uniqueIndex:idx_name"`
BIC string `json:"bic" gorm:"uniqueIndex:idx_name"`
}
type Operation struct {
gorm.Model
Debtor *Debtor
Creditor *Creditor
Type int `json:"type"`
Gateway string `json:"gateway"`
DebtorID int `json:"debtor_id"`
CreditorID int `json:"creditor_id"`
}
type Debtor struct {
gorm.Model
Name string `json:"name" gorm:"uniqueIndex:idx_name"`
IBAN string `json:"iban" gorm:"uniqueIndex:idx_name"`
}
Code
var err error
dsn := "root:changeme#tcp(localhost:3306)/mybb?charset=utf8mb4&parseTime=True&loc=Local"
conn, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
println(err.Error())
}
conn.AutoMigrate(Operation{})
op := make([]Operation, 0)
op = append(op, Operation{
Debtor: &Debtor{
IBAN: "test",
Name: "hey"},
Creditor: &Creditor{
Name: "otr",
BIC: "hello"},
Type: 2,
Gateway: "sepa",
})
op = append(op, Operation{
Debtor: &Debtor{
IBAN: "test",
Name: "hey",
},
Creditor: &Creditor{
Name: "otr",
BIC: "hello",
},
Type: 2,
Gateway: "sepa",
})
res := conn.Create(op)
if res.Error != nil {
println(res.Error.Error())
}
I'm now having a problem with getting an id of array feeds from database (Postgres) with Gorm.
How can I query and return id array feeds? I don't know how to get only id from struct without loop
feeds := []models.Feed{}
feedID := []string{}
db.Select("id").Where("user_id = ?", "admin1").Find(&feeds)
for _, feed := range feeds {
feedID = append(feedID, feed.ID)
}
utils.PrintStruct(feeds)
This is feed model file:
type Feed struct {
Model
Status string `json:"status"`
PublishAt *time.Time `json:"publishAt"`
UserID string `json:"userID,omitempty"`
}
This is model base data model using for data entity:
type Model struct {
ID string `json:"id" gorm:"primary_key"`
}
Result:
[
{
"id": "d95d4be5-b53c-4c70-aa09",
"status": "",
"publishAt": null,
"userID":""
},
{
"id": "84b2d46f-a24d-4854-b44d",
"status": "",
"publishAt": null,
"userID":""
}
]
But I want like this:
["d95d4be5-b53c-4c70-aa09","84b2d46f-a24d-4854-b44d"]
You can use pluck
var ids []string
db.Model(&Feed{}).Where("user_id = ?", "admin1").Pluck("id", &ids)
I have two tables,
SET search_path = public;
CREATE TABLE IF NOT EXISTS changelog
(
id BIGINT NOT NULL PRIMARY KEY,
object_type TEXT,
object_id BIGINT,
parent_type TEXT,
parent_id BIGINT,
action TEXT,
field TEXT,
old_value TEXT,
new_value TEXT,
comment_id INTEGER,
created_on TIMESTAMP WITHOUT TIME ZONE,
created_by BIGINT
);
CREATE TABLE IF NOT EXISTS changelog_comments
(
id INTEGER NOT NULL PRIMARY KEY,
comment TEXT,
created_on TIMESTAMP WITHOUT TIME ZONE,
created_by BIGINT
);
SET search_path = DEFAULT;
I want to implement a search method for the changelog which returns the fields
"objectType"
"objectId"
"parentType"
"parentId"
"action"
"field"
"oldValue"
"newValue"
"comment"
"createdBy"
"createdOn"
as you can see the result comes from the join of the two tables.
I found https://gorm.io/docs/preload.html but to be honest, didn't get that how can I achieve what I need.
I thought something like the following could be helpful
type ChangelogResponseItem struct {
ObjectType string `json:"objectType"`
ObjectID uuid.UUID `json:"objectId"`
ParentType string `json:"parentType"`
ParentID uuid.UUID `json:"parentId"`
Action string `json:"action"`
Field *string `json:"field"`
OldValue *string `json:"oldValue"`
NewValue *string `json:"newValue"`
Comment *string `json:"comment"`
CreatedBy *uint64 `json:"createdBy"`
CreatedOn *time.Time `json:"createdOn"`
}
The question is that how can get what I mentioned from the mentioned tables in GORM?
One way to do it would be to combine Joins and Select methods to get what you want. Based on your table, it would look something like this:
list := []ChangelogResponseItem{}
tx := db.Table("changelog").
Joins("INNER JOIN changelog_comments cc ON cc.id = changelog.comment_id").
Select("changelog.objectType, changelog.object_type, changelog.object_id, changelog.parent_type, changelog.parent_id, changelog.action, changelog.field, changelog.old_value, changelog.new_value, cc.comment, changelog.created_on, changelog.created_by").
Find(&list)
if tx.Error != nil {
// handle error
}
This is just to return the data, a search would include additional Where methods.
EDIT:
Solution with a preload option:
Structs:
type ChangelogComment struct {
ID uint64 `json:"id"`
Comment string `json:"comment"`
}
type Changelog struct {
ObjectType string `json:"objectType"`
ObjectID uuid.UUID `json:"objectId"`
ParentType string `json:"parentType"`
ParentID uuid.UUID `json:"parentId"`
Action string `json:"action"`
Field *string `json:"field"`
OldValue *string `json:"oldValue"`
NewValue *string `json:"newValue"`
CommentID uint64 `json:"comment_id"`
Comment *ChangelogComment `json:"comment"`
CreatedBy *uint64 `json:"createdBy"`
CreatedOn *time.Time `json:"createdOn"`
}
Code with the Preload method:
list := []Changelog{}
tx := db.Preload("Comment").Find(&list)
if tx.Error != nil {
// handle error
}
Please note that in this case, you will have a different JSON object, the structure od the object will not be flat, because you will have a comment field as well.
i have my model struct like the below :
type Detail struct {
Product
Stocks
}
type Product struct {
Name string `db:"name"`
Id int `db:"id"`
}
type Stocks {
Name string `db:"name"`
Price float `db:"price"`
Type string `db:"type"`
}
i would have a query to join the above tables like the below :
query, args, err := sqlx.In("select p.name , s.price from Product p,Stocks s where p.name=s.name and type IN (?)",typecodes)
query = s.Cmd.Db.Rebind(query)
var rows *sqlx.Rows
rows, err = s.Cmd.Db.Queryx(query, args...)
for rows.Next() {
var p model.Detail
err = rows.StructScan(&p)
}
Would like to know when i do rows.StructScan(&p) will the Product structure Name field be populated or will there be any ambuigity found for the same since Stocks also have a Name field ?
Currently i am not getting any result for the above.But when i comment the Name field in the Stocks struct, i am getting the data.
Let me know what i am missing here.
For ambiguous fields you're best annotating them with a prefix of their struct name, e.g. product_name, stock_name, then alias them appropriately in your SQL statement.
I.e.
type Detail struct {
Product
Stocks
}
type Product struct {
Name string `db:"product_name"`
Id int `db:"id"`
}
type Stocks {
Name string `db:"stock_name"`
Price float `db:"price"`
Type string `db:"type"`
}
And in your SQL:
SELECT p.name AS product_name, s.name AS stock_name, ... FROM Product p, Stocks s WHERE ...
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