Home > Back-end >  golang gorm upsert with returning
golang gorm upsert with returning

Time:12-30

In my golang project I use gorm and I need to make upsert query with returning clause to get the modified value from the query. I can make upsert, but I cannot figure out how to connect the returnning clause to it. The table name is counters, the code is as follows:

te := struct {
        Name string //key column
        Counter int
    }{
        Name: "name_to_update",
        Counter: 2,
    }

DB.
    //Model(te).
    Clauses(
        //clause.Returning{Columns: []clause.Column{{Name: "counter"}}},
        clause.OnConflict{
            Columns: []clause.Column{{Name: "name"}}, // key column
            DoUpdates: clause.Assignments(map[string]interface{}{
                "counter": gorm.Expr("counters.counter   ?", 1),
            }),
        },
    ).Create(&te)

The resulting SQL query is:

INSERT INTO "counters" ("counter", "name") VALUES (0, "name_to_update") ON CONFLICT ("name") 
DO UPDATE SET "counter"=counters.counter   1 RETURNING "name" //I need updated counter value here, not name  

So the counter is updated and this is OK, but it returns me the key column (in RETURNING) while I need the updated value of the counter. Any ideas how to fix it? Thank you

CodePudding user response:

I'm not sure if the anonymous struct causes an issue.

Also, it's unclear from your code where the table name - "counters" - comes from.

I've tried your solution - but with a dedicated struct for the model - and it works just fine.

type Counter struct {
    Name    string `gorm:"primaryKey"`
    Counter int
}

...

counter := Counter{Name: "name_to_update", Counter: 2}

    db.
        Clauses(
            clause.Returning{Columns: []clause.Column{{Name: "counter"}}},
            clause.OnConflict{
                Columns: []clause.Column{{Name: "name"}},
                DoUpdates: clause.Assignments(map[string]interface{}{
                    "counter": gorm.Expr("counters.counter   ?", 1),
                }),
            },
        ).Create(&counter)

    fmt.Println(counter.Counter)

The code above generates the following SQL

INSERT INTO "counters" ("name","counter") VALUES ('name_to_update',10) ON CONFLICT ("name") DO UPDATE SET "counter"=counters.counter   1 RETURNING "counter" 

And counter.Counter has correct updated value.

  • Related