I have a problem where Go is inserting "null" into my PostgreSQL database's jsonb columns if I try to do the following, and the structs property (in this case of type map[string]interface{}) is empty:
accessMembers, _ := json.Marshal(c.AccessMembers)
Doing a test print it outputs the same as the value which get stored into the database:
fmt.Println(string(accessMembers)) // equals the string "null"
The problem is that I need it to be - nil (not a string, but the Golang nil), so when I use it in the Exec function below:
sqlStr := `UPDATE my_table SET access_members=$1 WHERE id=$2;`
_, err := db.Exec(sqlStr, accessMembers, c.Id)
It should be the equivalent (which works!!) of doing:
_, err := db.Exec(sqlStr, nil, c.Id)
I tried a lot of different workarounds, which I thought had to work, but they didn't.
eg.
var accessMembers []byte
am, _ := json.Marshal(c.AccessMembers)
if string(am) != "null"{
accessMembers = am
}
sqlStr := `UPDATE my_table SET access_members=$1 WHERE id=$2;`
_, err := db.Exec(sqlStr, accessMembers, c.Id)
Which results in the following error: "pq: invalid input syntax for type json"
I can't understand why this is not the same, as explicitly writing nil in the Exec functions parameter, since the []byte clearly must be nil, right?
What am I doing wrong here? Here's how I had hoped it would work: http://play.golang.org/p/UoLAGfhhRl
Answer:
var accessMembers interface{} = nil
if c.AccessMembers != nil {
j, _ := json.Marshal(c.AccessMembers)
accessMembers = j
}
Thanks to thwd for providing the solution basically, and for pointing out how the database driver marshals nil differently, suggesting interface{} instead of []byte.
Thanks to DonSeba for reminding me to check if the struct field exists before using resources to marshal, do string conversion and comparison, which ought to be more expensive.
I can't understand why this is not the same, as explicitly writing nil in the Exec functions parameter, since the []byte clearly must be nil, right?
nil
has a type. The database driver marshals nil
differently for type map[string]interface{}
or []byte
than for interface{}
(which is the type of the second argument of db.Exec
). You should be able to do:
var i interface{} = nil
j, _ := json.Marshal(c.AccessMembers)
if string(j) != "null" {
i = j
}
sqlStr := `UPDATE content SET access_members=$1 WHERE id=$2;`
_, err := db.Exec(sqlStr, i, c.Id)
You have not initialized your AccessMembers
.
Before you decide to marshal the value you should check if it exists.
if c.AccessMembers == nil {
c.AccessMembers = make(map[string]interface{})
}
If you do the above, the result of :
accessMembers, err := json.Marshal(c.AccessMembers)
will be an valid empty json value {}
, and valid for storing into the db and retrieving the value later.
UPDATE :
there has been some discussion about the "NULL" value here : https://code.google.com/p/go/issues/detail?id=2278