समस्या यह है कि वर्तमान बीएसओएन कोडेक्स एन्कोडिंग/डिकोडिंग string
का समर्थन नहीं करते हैं में / से null
।
इसे संभालने का एक तरीका string
. के लिए एक कस्टम डिकोडर बनाना है टाइप करें जिसमें हम null
handle को हैंडल करते हैं मान:हम केवल खाली स्ट्रिंग का उपयोग करते हैं (और अधिक महत्वपूर्ण बात यह है कि त्रुटि की रिपोर्ट न करें)।
कस्टम डिकोडर का वर्णन bsoncodec.ValueDecoder
. प्रकार से किया जाता है . उन्हें bsoncodec.Registry
. पर पंजीकृत किया जा सकता है , एक bsoncodec.RegistryBuilder
. का उपयोग करके उदाहरण के लिए।
रजिस्ट्रियों को कई स्तरों पर सेट/लागू किया जा सकता है, यहां तक कि संपूर्ण mongo.Client
. पर भी , या किसी mongo.Database
. पर या सिर्फ एक mongo.Collection
. के लिए , उन्हें प्राप्त करते समय, उनके विकल्पों के भाग के रूप में, उदा. options.ClientOptions.SetRegistry()
।
सबसे पहले देखते हैं कि हम string
. के लिए यह कैसे कर सकते हैं , और आगे हम देखेंगे कि किसी भी प्रकार के समाधान को कैसे सुधारें/सामान्यीकृत करें।
null
तार
सबसे पहले चीज़ें, आइए एक कस्टम स्ट्रिंग डिकोडर बनाते हैं जो एक null
. को बदल सकता है एक (एन खाली) स्ट्रिंग में:
import (
"go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/bson/bsonrw"
"go.mongodb.org/mongo-driver/bson/bsontype"
)
type nullawareStrDecoder struct{}
func (nullawareStrDecoder) DecodeValue(dctx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Kind() != reflect.String {
return errors.New("bad type or not settable")
}
var str string
var err error
switch vr.Type() {
case bsontype.String:
if str, err = vr.ReadString(); err != nil {
return err
}
case bsontype.Null: // THIS IS THE MISSING PIECE TO HANDLE NULL!
if err = vr.ReadNull(); err != nil {
return err
}
default:
return fmt.Errorf("cannot decode %v into a string type", vr.Type())
}
val.SetString(str)
return nil
}
ठीक है, और अब देखते हैं कि इस कस्टम स्ट्रिंग डिकोडर का उपयोग mongo.Client
में कैसे करें :
clientOpts := options.Client().
ApplyURI("mongodb://localhost:27017/").
SetRegistry(
bson.NewRegistryBuilder().
RegisterDecoder(reflect.TypeOf(""), nullawareStrDecoder{}).
Build(),
)
client, err := mongo.Connect(ctx, clientOpts)
अब से, इस client
का उपयोग करते हुए , जब भी आप परिणामों को string
. में डिकोड करते हैं मान, यह पंजीकृत nullawareStrDecoder
डिकोडर को रूपांतरण को संभालने के लिए बुलाया जाएगा, जो bson null
को स्वीकार करता है मान और गो खाली स्ट्रिंग सेट करता है ""
।
लेकिन हम बेहतर कर सकते हैं... आगे पढ़ें...
<एच3>2. हैंडलिंगnull
किसी भी प्रकार के मान:"टाइप-न्यूट्रल" नल-अवेयर डिकोडर एक तरीका यह होगा कि एक अलग, कस्टम डिकोडर बनाया जाए और इसे प्रत्येक प्रकार के लिए पंजीकृत किया जाए जिसे हम संभालना चाहते हैं। ऐसा लगता है कि यह बहुत काम है।
इसके बजाय हम जो कर सकते हैं (और करना चाहिए) वह एक एकल, "टाइप-न्यूट्रल" कस्टम डिकोडर बनाना है जो केवल null
को हैंडल करता है। s, और यदि BSON मान null
नहीं है , गैर को संभालने के लिए डिफ़ॉल्ट डिकोडर को कॉल करना चाहिए-null
मूल्य।
यह आश्चर्यजनक रूप से सरल है:
type nullawareDecoder struct {
defDecoder bsoncodec.ValueDecoder
zeroValue reflect.Value
}
func (d *nullawareDecoder) DecodeValue(dctx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if vr.Type() != bsontype.Null {
return d.defDecoder.DecodeValue(dctx, vr, val)
}
if !val.CanSet() {
return errors.New("value not settable")
}
if err := vr.ReadNull(); err != nil {
return err
}
// Set the zero value of val's type:
val.Set(d.zeroValue)
return nil
}
हमें बस यह पता लगाना है कि nullawareDecoder.defDecoder
के लिए क्या उपयोग करना है . इसके लिए हम डिफ़ॉल्ट रजिस्ट्री का उपयोग कर सकते हैं:bson.DefaultRegistry
, हम अलग-अलग प्रकारों के लिए डिफ़ॉल्ट डिकोडर देख सकते हैं। कूल।
तो अब हम जो करते हैं वह हमारे nullawareDecoder
. का एक मान पंजीकृत करता है सभी प्रकार के लिए हम null
handle को हैंडल करना चाहते हैं एस के लिए। यह इतना मुश्किल नही है। हम केवल उन प्रकारों (या उन प्रकारों के मान) को सूचीबद्ध करते हैं जिनके लिए हम चाहते हैं, और हम एक साधारण लूप के साथ सभी का ध्यान रख सकते हैं:
customValues := []interface{}{
"", // string
int(0), // int
int32(0), // int32
}
rb := bson.NewRegistryBuilder()
for _, v := range customValues {
t := reflect.TypeOf(v)
defDecoder, err := bson.DefaultRegistry.LookupDecoder(t)
if err != nil {
panic(err)
}
rb.RegisterDecoder(t, &nullawareDecoder{defDecoder, reflect.Zero(t)})
}
clientOpts := options.Client().
ApplyURI("mongodb://localhost:27017/").
SetRegistry(rb.Build())
client, err := mongo.Connect(ctx, clientOpts)
ऊपर के उदाहरण में मैंने string
. के लिए नल-जागरूक डिकोडर पंजीकृत किए हैं , int
और int32
, लेकिन आप इस सूची को अपनी पसंद के अनुसार बढ़ा सकते हैं, बस वांछित प्रकारों के मान customValues
में जोड़ें ऊपर का टुकड़ा।