JSON поля из sqlite3 в Голанге
У меня есть поле JSON в коллекции sqlite3. Моя схема выглядит так:
CREATE Table Animals(
id int,
sounds json,
name string
)
Я понимаю, что интерфейс go-sqlite не поддерживает явно тип данных json. Однако мой json довольно прост, поскольку все поля являются массивами json, например;
["bark", "woof", "growl"]
["meow", "hiss", "growl"]
Таким образом, полная запись может быть:
id sounds name
1 ["bark", "woof", "growl"] Fido
2 ["meow", "hiss", "growl"] Rufus
Используя пакет:
_ "github.com/mattn/go-sqlite3"
Я могу извлечь свое поле JSON с
var id sql.NullInt64
var name sql.NullString
var sounds []uint8
err := db.QueryRow("SELECT id,name,sounds FROM Animals WHERE id = ?;", 1).Scan(&id, &name, &sounds)
fmt.Println(strconv.Itoa(id) + "|" + name + "|" + strings.Join(sounds, "+"))
// does print correctly:
1|Fido|bark+wood+growl
То есть, кажется, что sqlite3 json хранится в строке юникода (?) В виде серии... байтов?..., которую я могу преобразовать в строку с помощью модуля String. Кроме того, мне интересна операция соединения "+", чтобы я мог сделать из этого запрос + строку + поиск + для другого приложения ниже по течению.
Однако мне бы очень хотелось объединить все это в JSON и использовать преимущества разборчивости / разбора JSON, а не специальные пользовательские распечатки. Когда я пытаюсь:
type Animal struct {
id int `json:"id"`
name sql.NullString `json:"name"`
sounds []uint8 `json:"sounds"`
}
var a Animal
err := db.QueryRow("SELECT id,name,sounds FROM Animals WHERE id = ?;", 1).Scan(&a.id, &a.name, &a.sounds
)
Он печатает истинный массив целых чисел. Как я могу встроить объявление strings.Join(sounds []uint8) + преобразование функции в мое определение типа с поддержкой json?
Кроме того, мне не ясно, как использовать строку [] uint8 в том случае, если json равен nulled [] или true NULL, и дополнительно сделать ее устойчивой к ним.
Некоторые ссылки:
1 ответ
Ваш вопрос поднимает несколько тем. Но самый простой ответ на все из них:
Не используйте реляционную базу данных.
Похоже, вы хотите получать объекты / документы, поэтому использование механизма хранения, который изначально поддерживает это, избавит вас от необходимости использовать ключи везде. MongoDB, CouchDB или какое-либо другое решение NoSQL, вероятно, подходит для ваших потребностей.
Но, сказав это, есть ответы на ваши конкретные вопросы. Вместе взятые, они, возможно, делают что-то сложное и уродливое, хотя.
Ваш
sounds
тип.Создайте пользовательский тип, который реализует интерфейс sql.Scanner и отменяет маршализацию значения JSON для вас:
type Sounds []string func (s *Sounds) Scan(src interface{}) error { switch t := src.(type) { case []byte: return json.Unmarshal(t, &s) default: return errors.New("Invalid type") } }
Сканирование в структуру
Используйте sqlx для этого. Это позволяет вам сканировать всю строку в структуру гораздо проще, чем стандартная библиотека. Он может использовать
db
тег для сопоставления строк с полем структуры.Единая структура для БД и JSON
Вы можете иметь несколько тегов в своей структуре:
type Animal struct { id int `db:"id" json:"id"` name sql.NullString `db:"name" json:"name"` sounds []uint8 `db:"sounds" json:"sounds"` }