You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在应用层校验Go结构体/bson.M与MongoDB JSON Schema?

Go应用层校验MongoDB JSON Schema方案

针对你提到的两种数据类型(Go结构体Person和bson.M),可以通过以下库和方法在应用层完成MongoDB JSON Schema的校验,实现提前失败并支持测试:

1. 使用gojsonschema库(推荐)

这是Go生态中成熟的JSON Schema校验库,支持JSON Schema Draft 04/06/07规范,能直接对接MongoDB的JSON Schema定义。

校验bson.M类型

将bson.M序列化为MongoDB兼容的扩展JSON,再传入库中校验:

import (
    "fmt"
    "github.com/xeipuuv/gojsonschema"
    "go.mongodb.org/mongo-driver/bson"
)

// 定义MongoDB的JSON Schema
var mongoSchema = gojsonschema.NewStringLoader(`{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer", "minimum": 0}
    },
    "required": ["name"]
}`)

func ValidateBsonM(data bson.M) error {
    // 将bson.M转为MongoDB扩展JSON
    jsonBytes, err := bson.MarshalExtJSON(data, false, false)
    if err != nil {
        return fmt.Errorf("序列化bson.M失败: %w", err)
    }
    documentLoader := gojsonschema.NewBytesLoader(jsonBytes)
    
    result, err := gojsonschema.Validate(mongoSchema, documentLoader)
    if err != nil {
        return fmt.Errorf("Schema校验出错: %w", err)
    }
    
    if !result.Valid() {
        var errMsgs []string
        for _, err := range result.Errors() {
            errMsgs = append(errMsgs, err.String())
        }
        return fmt.Errorf("数据不符合Schema规则: %v", errMsgs)
    }
    return nil
}

校验Person结构体

先将结构体实例序列化为JSON(确保字段标签与Schema对应),再执行校验:

import "encoding/json"

type Person struct {
    Name string `bson:"name" json:"name"` // 同时指定bson和json标签,保证序列化一致性
    Age  int    `bson:"age" json:"age"`
}

func ValidatePerson(p Person) error {
    jsonBytes, err := json.Marshal(p)
    if err != nil {
        return fmt.Errorf("序列化Person失败: %w", err)
    }
    documentLoader := gojsonschema.NewBytesLoader(jsonBytes)
    
    result, err := gojsonschema.Validate(mongoSchema, documentLoader)
    if err != nil {
        return fmt.Errorf("Schema校验出错: %w", err)
    }
    
    if !result.Valid() {
        var errMsgs []string
        for _, err := range result.Errors() {
            errMsgs = append(errMsgs, err.String())
        }
        return fmt.Errorf("数据不符合Schema规则: %v", errMsgs)
    }
    return nil
}

2. 自定义校验逻辑(轻量场景)

如果不想依赖第三方库,可以手动解析MongoDB的JSON Schema,针对两种数据类型编写校验逻辑:

  • 对于Person结构体:利用反射遍历字段,对照Schema的类型、必填项、范围等规则逐一校验。
  • 对于bson.M:直接遍历键值对,匹配Schema定义的规则进行校验。

这种方式适合Schema规则简单的场景,灵活性高但需要自己实现完整的校验逻辑。

3. 应用层测试支持

不管采用哪种方案,都可以编写单元测试用例验证校验逻辑:

import "testing"

func TestValidatePerson(t *testing.T) {
    // 测试合法数据
    validPerson := Person{Name: "Bob", Age: 28}
    if err := ValidatePerson(validPerson); err != nil {
        t.Fatalf("合法Person校验失败: %v", err)
    }

    // 测试非法数据(缺少必填字段name)
    invalidPerson := Person{Age: 17}
    if err := ValidatePerson(invalidPerson); err == nil {
        t.Fatal("缺少name的Person应该校验失败")
    }
}

func TestValidateBsonM(t *testing.T) {
    // 测试合法数据
    validData := bson.M{"name": "Charlie", "age": 35}
    if err := ValidateBsonM(validData); err != nil {
        t.Fatalf("合法bson.M校验失败: %v", err)
    }

    // 测试非法数据(age为负数)
    invalidData := bson.M{"name": "Dave", "age": -5}
    if err := ValidateBsonM(invalidData); err == nil {
        t.Fatal("age为负数的bson.M应该校验失败")
    }
}

内容的提问来源于stack exchange,提问作者Alexander Mills

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:55:28