MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Làm cách nào để bỏ qua null trong khi giải nén tài liệu MongoDB?

Vấn đề là codec bson hiện tại không hỗ trợ mã hóa / giải mã string thành / từ null .

Một cách để xử lý điều này là tạo bộ giải mã tùy chỉnh cho string nhập vào đó chúng tôi xử lý null giá trị:chúng tôi chỉ sử dụng chuỗi trống (và quan trọng hơn là không báo lỗi).

Bộ giải mã tùy chỉnh được mô tả bằng loại bsoncodec.ValueDecoder . Chúng có thể được đăng ký tại bsoncodec.Registry , sử dụng bsoncodec.RegistryBuilder chẳng hạn.

Đăng ký có thể được đặt / áp dụng ở nhiều cấp, thậm chí cho toàn bộ mongo.Client hoặc tới một mongo.Database hoặc chỉ tới một mongo.Collection , khi có được chúng, như một phần của các lựa chọn, ví dụ:options.ClientOptions.SetRegistry() .

Trước tiên, hãy xem cách chúng ta có thể thực hiện việc này cho string và tiếp theo, chúng ta sẽ xem cách cải thiện / tổng quát hóa giải pháp cho bất kỳ loại nào.

1. Xử lý null chuỗi

Điều đầu tiên, hãy tạo một bộ giải mã chuỗi tùy chỉnh có thể biến null thành một chuỗi (n rỗng):

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
}

OK, và bây giờ chúng ta hãy xem cách sử dụng bộ giải mã chuỗi tùy chỉnh này cho mongo.Client :

clientOpts := options.Client().
    ApplyURI("mongodb://localhost:27017/").
    SetRegistry(
        bson.NewRegistryBuilder().
            RegisterDecoder(reflect.TypeOf(""), nullawareStrDecoder{}).
            Build(),
    )
client, err := mongo.Connect(ctx, clientOpts)

Từ bây giờ, sử dụng client này , bất cứ khi nào bạn giải mã kết quả thành chuỗi string giá trị, nullawareStrDecoder đã đăng ký này bộ giải mã sẽ được gọi để xử lý chuyển đổi, chấp nhận bson null giá trị và đặt chuỗi trống "" .

Nhưng chúng tôi có thể làm tốt hơn ... Đọc tiếp ...

2. Xử lý null các giá trị thuộc bất kỳ loại nào:bộ giải mã nhận biết null "loại trung tính"

Một cách sẽ là tạo một bộ giải mã tùy chỉnh, riêng biệt và đăng ký nó cho từng loại mà chúng tôi muốn xử lý. Đó dường như là rất nhiều công việc.

Thay vào đó, những gì chúng tôi có thể (và nên) làm là tạo một bộ giải mã tùy chỉnh "loại trung tính" duy nhất, chỉ xử lý null s và nếu giá trị BSON không phải là null , nên gọi bộ giải mã mặc định để xử lý không phải null giá trị.

Điều này đơn giản một cách đáng ngạc nhiên:

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
}

Chúng tôi chỉ phải tìm ra những gì sẽ sử dụng cho nullawareDecoder.defDecoder . Đối với điều này, chúng tôi có thể sử dụng sổ đăng ký mặc định:bson.DefaultRegistry , chúng tôi có thể tra cứu bộ giải mã mặc định cho các loại riêng lẻ. Thật tuyệt.

Vì vậy, những gì chúng tôi làm bây giờ là đăng ký một giá trị của nullawareDecoder của chúng tôi cho tất cả các loại mà chúng tôi muốn xử lý null s cho. Nó không khó lắm đâu. Chúng tôi chỉ liệt kê các loại (hoặc giá trị của các loại đó) mà chúng tôi muốn điều này và chúng tôi có thể xử lý tất cả bằng một vòng lặp đơn giản:

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)

Trong ví dụ trên, tôi đã đăng ký bộ giải mã nhận biết null cho string , intint32 , nhưng bạn có thể mở rộng danh sách này theo ý thích của mình, chỉ cần thêm giá trị của các loại mong muốn vào customValues lát trên.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB khóa ghi ở cấp độ nào? (hoặc:ý nghĩa của nó theo mỗi kết nối

  2. Flask - Yêu cầu không hợp lệ Trình duyệt (hoặc proxy) đã gửi một yêu cầu mà máy chủ này không thể hiểu được

  3. Bộ bản sao MongoDB với xác thực mật khẩu đơn giản

  4. Làm thế nào để sắp xếp các tài liệu con trong trường mảng?

  5. Tại sao MongoDB lại chiếm quá nhiều dung lượng?