整理空的map [string] interface {}会导致结果为“ null”而不是nil

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