MongoDB 未在存储值之前对其进行编组
MongoDB is not marshaling a value before storing it
我正在使用自定义 JSON marshaller/unmarshaller 在 Go 中进行整数和字符串之间的映射。问题是值作为整数而不是字符串存储在数据库中。在下面的示例中,我希望它存储在 MongoDB 数据库中:
{ "_id" : "id123", "desc" : "Red Delicious", "value" : "apple" }
相反,我得到:
{ "_id" : "id123", "desc" : "Red Delicious", "value" : 1 }
如测试所示,编组和解组工作正常。怎么回事?
这是一个 Go 测试示例(保存到 unmarshal_test.go 和 "go test")。
package testunmarshal
import (
"fmt"
"testing"
"encoding/json"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Const int
const (
Apple Const = 1
Banana = 2
Cherry = 4
)
type Record struct {
Id string `bson:"_id" json:"id"`
Desc string `bson:"desc" json:"desc"`
Value Const `bson:"value" json:"value`
}
func (intValue Const) Code() string {
switch intValue {
case Apple: return "apple"
case Banana: return "banana"
case Cherry: return "cherry"
}
return "invalid"
}
func (intValue *Const) UnmarshalJSON(data []byte) (err error) {
switch string(data) {
case `"apple"`:
*intValue = Apple
case `"banana"`:
*intValue = Banana
case `"cherry"`:
*intValue = Cherry
default:
return fmt.Errorf("Invalid fruit %s", data)
}
return nil
}
func (intValue *Const) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, intValue.Code())), nil
}
func TestMarshalJSON(t *testing.T) {
var orig = Record {
Id: "id456",
Desc: "Cavendish",
Value: Banana,
}
var copy Record
bytes, err := json.Marshal(&orig)
if err != nil {
t.Errorf("Marshal failed: %s", err.Error())
return
}
err = json.Unmarshal(bytes, ©)
if err != nil {
t.Errorf("Unmarshal failed: %s", err.Error())
return
}
if orig.Value != copy.Value {
t.Errorf("Expected %d=%s, got %d=%s", orig.Value, orig.Value.Code(), copy.Value, copy.Value.Code())
}
}
func TestMarshalBSON(t *testing.T) {
var orig = Record {
Id: "id456",
Desc: "Cavendish",
Value: Banana,
}
var copy Record
bytes, err := bson.Marshal(&orig)
if err != nil {
t.Errorf("Marshal failed: %s", err.Error())
return
}
err = bson.Unmarshal(bytes, ©)
if err != nil {
t.Errorf("Unmarshal failed: %s", err.Error())
return
}
if orig.Value != copy.Value {
t.Errorf("Expected %d=%s, got %d=%s", orig.Value, orig.Value.Code(), copy.Value, copy.Value.Code())
}
}
func TestMongo(t *testing.T) {
var rec1 = Record {
Id: "id123",
Desc: "Red Delicious",
Value: Apple,
}
var rec2 Record
sess, err := mgo.Dial("localhost")
if err != nil {
t.Errorf(err.Error())
return
}
db := sess.DB("test")
if db == nil {
t.Fatal("Failed to connect to database")
return
}
col := db.C("fruit")
if col == nil {
t.Fatal("Failed to open collection")
return
}
// defer col.DropCollection()
err = col.Insert(&rec1)
if err != nil {
t.Fatal("Failed to insert: %s", err.Error())
return
}
err = col.Find(bson.M{}).One(&rec2)
if err != nil {
t.Fatal("Failed to retrieve stored object: %s", err.Error())
return
}
if rec1.Value != rec2.Value {
t.Errorf("Expected %d=%s, got %d=%s", rec1.Value, rec1.Value.Code(), rec1.Value, rec2.Value.Code())
}
}
编辑:添加了更多测试以证明编组和解组工作正常。
bson 编码器不使用 JSON 编组接口。实现Getter接口:
func (intValue Const) GetBSON() (interface{}, error) {
return intValue.Code(), nil
}
您还需要实现 Setter 接口。
func (intValue *Const) SetBSON(raw bson.Raw) error {
var data int
if err := raw.Unmarshal(&data); err != nil {
return err
}
switch data {
case `"apple"`:
*intValue = Apple
case `"banana"`:
*intValue = Banana
case `"cherry"`:
*intValue = Cherry
default:
return fmt.Errorf("Invalid fruit %s", data)
}
return nil
}
我正在使用自定义 JSON marshaller/unmarshaller 在 Go 中进行整数和字符串之间的映射。问题是值作为整数而不是字符串存储在数据库中。在下面的示例中,我希望它存储在 MongoDB 数据库中:
{ "_id" : "id123", "desc" : "Red Delicious", "value" : "apple" }
相反,我得到:
{ "_id" : "id123", "desc" : "Red Delicious", "value" : 1 }
如测试所示,编组和解组工作正常。怎么回事?
这是一个 Go 测试示例(保存到 unmarshal_test.go 和 "go test")。
package testunmarshal
import (
"fmt"
"testing"
"encoding/json"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Const int
const (
Apple Const = 1
Banana = 2
Cherry = 4
)
type Record struct {
Id string `bson:"_id" json:"id"`
Desc string `bson:"desc" json:"desc"`
Value Const `bson:"value" json:"value`
}
func (intValue Const) Code() string {
switch intValue {
case Apple: return "apple"
case Banana: return "banana"
case Cherry: return "cherry"
}
return "invalid"
}
func (intValue *Const) UnmarshalJSON(data []byte) (err error) {
switch string(data) {
case `"apple"`:
*intValue = Apple
case `"banana"`:
*intValue = Banana
case `"cherry"`:
*intValue = Cherry
default:
return fmt.Errorf("Invalid fruit %s", data)
}
return nil
}
func (intValue *Const) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, intValue.Code())), nil
}
func TestMarshalJSON(t *testing.T) {
var orig = Record {
Id: "id456",
Desc: "Cavendish",
Value: Banana,
}
var copy Record
bytes, err := json.Marshal(&orig)
if err != nil {
t.Errorf("Marshal failed: %s", err.Error())
return
}
err = json.Unmarshal(bytes, ©)
if err != nil {
t.Errorf("Unmarshal failed: %s", err.Error())
return
}
if orig.Value != copy.Value {
t.Errorf("Expected %d=%s, got %d=%s", orig.Value, orig.Value.Code(), copy.Value, copy.Value.Code())
}
}
func TestMarshalBSON(t *testing.T) {
var orig = Record {
Id: "id456",
Desc: "Cavendish",
Value: Banana,
}
var copy Record
bytes, err := bson.Marshal(&orig)
if err != nil {
t.Errorf("Marshal failed: %s", err.Error())
return
}
err = bson.Unmarshal(bytes, ©)
if err != nil {
t.Errorf("Unmarshal failed: %s", err.Error())
return
}
if orig.Value != copy.Value {
t.Errorf("Expected %d=%s, got %d=%s", orig.Value, orig.Value.Code(), copy.Value, copy.Value.Code())
}
}
func TestMongo(t *testing.T) {
var rec1 = Record {
Id: "id123",
Desc: "Red Delicious",
Value: Apple,
}
var rec2 Record
sess, err := mgo.Dial("localhost")
if err != nil {
t.Errorf(err.Error())
return
}
db := sess.DB("test")
if db == nil {
t.Fatal("Failed to connect to database")
return
}
col := db.C("fruit")
if col == nil {
t.Fatal("Failed to open collection")
return
}
// defer col.DropCollection()
err = col.Insert(&rec1)
if err != nil {
t.Fatal("Failed to insert: %s", err.Error())
return
}
err = col.Find(bson.M{}).One(&rec2)
if err != nil {
t.Fatal("Failed to retrieve stored object: %s", err.Error())
return
}
if rec1.Value != rec2.Value {
t.Errorf("Expected %d=%s, got %d=%s", rec1.Value, rec1.Value.Code(), rec1.Value, rec2.Value.Code())
}
}
编辑:添加了更多测试以证明编组和解组工作正常。
bson 编码器不使用 JSON 编组接口。实现Getter接口:
func (intValue Const) GetBSON() (interface{}, error) {
return intValue.Code(), nil
}
您还需要实现 Setter 接口。
func (intValue *Const) SetBSON(raw bson.Raw) error {
var data int
if err := raw.Unmarshal(&data); err != nil {
return err
}
switch data {
case `"apple"`:
*intValue = Apple
case `"banana"`:
*intValue = Banana
case `"cherry"`:
*intValue = Cherry
default:
return fmt.Errorf("Invalid fruit %s", data)
}
return nil
}