Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I work with SQL NULL values and JSON in a good way?

Tags:

json

sql

go

Go types like Int64 and String cannot store null values, so I found I could use sql.NullInt64 and sql.NullString for this.

But when I use these in a Struct, and generate JSON from the Struct with the json package, then the format is different to when I use regular Int64 and String types.

The JSON has an additional level because the sql.Null*** is also a Struct.

Is there a good workaround for this, or should I not use NULLs in my SQL database?

like image 221
Alex Avatar asked Oct 12 '15 01:10

Alex


People also ask

How do we work with NULL values in SQL?

A field with a NULL value is a field with no value. If a field in a table is optional, it is possible to insert a new record or update a record without adding a value to this field. Then, the field will be saved with a NULL value. Note: A NULL value is different from a zero value or a field that contains spaces.

How do I allow NULL values in JSON?

To include null values in the JSON output of the FOR JSON clause, specify the INCLUDE_NULL_VALUES option. If you don't specify the INCLUDE_NULL_VALUES option, the JSON output doesn't include properties for values that are null in the query results.

Can we have NULL value in JSON?

JSON has a special value called null which can be set on any type of data including arrays, objects, number and boolean types.

Is it okay to have NULL values in SQL?

You can use NULL values for any data type including integers, decimals, strings, or blobs. Even though many database administrators use NULL, they usually demand that NULLs are not used for numeric values. The reason is that NULLs used for numeric values can become confusing when developing code to calculate data.


1 Answers

Types like sql.NullInt64 do not implement any special handling for JSON marshaling or unmarshaling, so the default rules apply. Since the type is a struct, it gets marshalled as an object with its fields as attributes.

One way to work around this is to create your own type that implements the json.Marshaller / json.Unmarshaler interfaces. By embedding the sql.NullInt64 type, we get the SQL methods for free. Something like this:

type JsonNullInt64 struct {     sql.NullInt64 }  func (v JsonNullInt64) MarshalJSON() ([]byte, error) {     if v.Valid {         return json.Marshal(v.Int64)     } else {         return json.Marshal(nil)     } }  func (v *JsonNullInt64) UnmarshalJSON(data []byte) error {     // Unmarshalling into a pointer will let us detect null     var x *int64     if err := json.Unmarshal(data, &x); err != nil {         return err     }     if x != nil {         v.Valid = true         v.Int64 = *x     } else {         v.Valid = false     }     return nil } 

If you use this type in place of sql.NullInt64, it should be encoded as you expect.

You can test this example here: http://play.golang.org/p/zFESxLcd-c

like image 77
James Henstridge Avatar answered Sep 23 '22 01:09

James Henstridge