陈明勇一名热爱技术、乐于分享的开发者,同时也是开源爱好者。
90文章
12分类
21标签
19评论
157点赞
96496浏览量
1
0
Go Mongox:轻松实现 MongoDB 时间字段自动填充
陈明勇
2025-02-10 15:34:14
阅读 52

扫码关注公众号,手机阅读更方便

Go技术干货

前言

MongoDB 的集合中,时间字段(如 创建时间更新时间)通常是必不可少的。在使用 Go 语言操作 MongoDB 时,例如执行插入或更新操作,我们需要手动设置这些时间字段的值。然而,每次手动赋值不仅繁琐,还容易导致代码重复。那么,是否可以在程序层面实现自动填充呢?目前,官方的 mongo-go-driver 并不支持自动填充时间字段,而 mongox 库提供了这一能力。本文将介绍如何使用 mongox 库,在插入和更新数据时自动填充时间字段,从而提升开发效率并减少重复代码。

准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。

let's go

时间字段填充规则

在定义结构体时,如果字段符合以下特性,则可以被自动填充:

  • 字段名称和类型符合规定
    • 结构体字段名为 CreatedAtUpdatedAt 字段,且类型为 time.Timeint/int64。当为 int/int64 时,将会填充当前时间戳秒数。
  • 字段包含特定标签
    • mongox:"autoCreateTime":在插入文档时,如果该字段的值为零值,则会自动设置为当前时间。除了 time.Time 类型,你还可以使用 secondmillinano 三种时间戳精度,使用样例:mongox:"autoCreateTime:milli" 如果不指定 milli,默认是 second
    • mongox:"autoUpdateTime":在插入文档时,如果该字段的值为零值或更新文档时,会自动设置为当前时间。除了 time.Time 类型,你还可以使用 secondmillinano 三种时间戳精度。使用样例:mongox:"autoUpdateTime:milli" 如果不指定 milli,默认是 second

Mongox 的安装

通过以下命令安装 mongox 库:

go get github.com/chenmingyong0423/go-mongox/v2

使用 Mongox 进行插入操作

  • 结构体定义
    type User struct {
        ID        bson.ObjectID `bson:"_id,omitempty" mongox:"autoID"`
        Name      string        `bson:"name"`
        Age       int           `bson:"age"`
        CreatedAt time.Time     `bson:"created_at"`
        UpdatedAt int           `bson:"updated_at"` // 使用秒级时间戳填充字段
    
        CreateSecondTime int64 `bson:"create_second_time" mongox:"autoCreateTime"`        // 使用秒级时间戳填充字段
        UpdateSecondTime int64 `bson:"update_second_time" mongox:"autoUpdateTime:second"` // 使用秒级时间戳填充字段
        CreateMilliTime  int64 `bson:"create_milli_time" mongox:"autoCreateTime:milli"`   // 使用毫秒级时间戳填充字段
        UpdateMilliTime  int64 `bson:"update_milli_time" mongox:"autoUpdateTime:milli"`   // 使用毫秒级时间戳填充字段
        CreateNanoTime   int64 `bson:"create_nano_time" mongox:"autoCreateTime:nano"`     // 使用纳秒级时间戳填充字段
        UpdateNanoTime   int64 `bson:"update_nano_time" mongox:"autoUpdateTime:nano"`     // 使用纳秒级时间戳填充字段
    }
    
  • 示例代码
    package main
    
    import (
        "context"
        "fmt"
        "time"
    
        "go.mongodb.org/mongo-driver/v2/bson"
    
        "go.mongodb.org/mongo-driver/v2/mongo"
        "go.mongodb.org/mongo-driver/v2/mongo/options"
        "go.mongodb.org/mongo-driver/v2/mongo/readpref"
    
        "github.com/chenmingyong0423/go-mongox/v2"
    )
    
    type User struct {
        ID        bson.ObjectID `bson:"_id,omitempty" mongox:"autoID"`
        Name      string        `bson:"name"`
        Age       int           `bson:"age"`
        CreatedAt time.Time     `bson:"created_at"`
        UpdatedAt int           `bson:"updated_at"` // 使用秒级时间戳填充字段
    
        CreateSecondTime int64 `bson:"create_second_time" mongox:"autoCreateTime"`        // 使用秒级时间戳填充字段
        UpdateSecondTime int64 `bson:"update_second_time" mongox:"autoUpdateTime:second"` // 使用秒级时间戳填充字段
        CreateMilliTime  int64 `bson:"create_milli_time" mongox:"autoCreateTime:milli"`   // 使用毫秒级时间戳填充字段
        UpdateMilliTime  int64 `bson:"update_milli_time" mongox:"autoUpdateTime:milli"`   // 使用毫秒级时间戳填充字段
        CreateNanoTime   int64 `bson:"create_nano_time" mongox:"autoCreateTime:nano"`     // 使用纳秒级时间戳填充字段
        UpdateNanoTime   int64 `bson:"update_nano_time" mongox:"autoUpdateTime:nano"`     // 使用纳秒级时间戳填充字段
    }
    
    func main() {
        mongoClient, err := newMongoClient()
        if err != nil {
            panic(err)
        }
        client := mongox.NewClient(mongoClient, &mongox.Config{})
        database := client.NewDatabase("db-test")
    
        userColl := mongox.NewCollection[User](database, "users")
    
        user := &User{
            Name: "陈明勇",
            Age:  18,
        }
        _, err = userColl.Creator().InsertOne(context.Background(), user)
        if err != nil {
            panic(err)
        }
        fmt.Println(!user.CreatedAt.IsZero())   // true
        fmt.Println(user.UpdatedAt != 0)        // true
        fmt.Println(user.CreateSecondTime != 0) // true
        fmt.Println(user.UpdateSecondTime != 0) // true
        fmt.Println(user.CreateMilliTime != 0)  // true
        fmt.Println(user.UpdateMilliTime != 0)  // true
        fmt.Println(user.CreateNanoTime != 0)   // true
        fmt.Println(user.UpdateNanoTime != 0)   // true
    }
    
    // 示例代码,仅供参考
    func newMongoClient() (*mongo.Client, error) {
        client, err := mongo.Connect(options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(options.Credential{
            Username:   "test",
            Password:   "test",
            AuthSource: "db-test",
        }))
        if err != nil {
            return nil, err
        }
        err = client.Ping(context.Background(), readpref.Primary())
        if err != nil {
            panic(err)
        }
        return client, nil
    }
    
    

插入数据后,通过零值比较判断字段值是否被填充。fmt.Println 语句都输出 true,说明所有时间字段的值都被填充。

使用 Mongox 进行更新操作

  • 更新操作
    package main
    
    import (
        "context"
        "fmt"
        "time"
    
        "github.com/chenmingyong0423/go-mongox/v2/builder/query"
        "github.com/chenmingyong0423/go-mongox/v2/builder/update"
    
        "go.mongodb.org/mongo-driver/v2/bson"
    
        "go.mongodb.org/mongo-driver/v2/mongo"
        "go.mongodb.org/mongo-driver/v2/mongo/options"
        "go.mongodb.org/mongo-driver/v2/mongo/readpref"
    
        "github.com/chenmingyong0423/go-mongox/v2"
    )
    
    type User struct {
        ID        bson.ObjectID `bson:"_id,omitempty" mongox:"autoID"`
        Name      string        `bson:"name"`
        Age       int           `bson:"age"`
        CreatedAt time.Time     `bson:"created_at"`
        UpdatedAt int           `bson:"updated_at"` // 使用秒级时间戳填充字段
    
        CreateSecondTime int64 `bson:"create_second_time" mongox:"autoCreateTime"`        // 使用秒级时间戳填充字段
        UpdateSecondTime int64 `bson:"update_second_time" mongox:"autoUpdateTime:second"` // 使用秒级时间戳填充字段
        CreateMilliTime  int64 `bson:"create_milli_time" mongox:"autoCreateTime:milli"`   // 使用毫秒级时间戳填充字段
        UpdateMilliTime  int64 `bson:"update_milli_time" mongox:"autoUpdateTime:milli"`   // 使用毫秒级时间戳填充字段
        CreateNanoTime   int64 `bson:"create_nano_time" mongox:"autoCreateTime:nano"`     // 使用纳秒级时间戳填充字段
        UpdateNanoTime   int64 `bson:"update_nano_time" mongox:"autoUpdateTime:nano"`     // 使用纳秒级时间戳填充字段
    }
    
    func main() {
        mongoClient, err := newMongoClient()
        if err != nil {
            panic(err)
        }
        client := mongox.NewClient(mongoClient, &mongox.Config{})
        database := client.NewDatabase("db-test")
    
        userColl := mongox.NewCollection[User](database, "users")
    
        // 用于比较后面的时间字段是否更新
        now := time.Now()
    
        _, err = userColl.Updater().
            Filter(query.Eq("name", "陈明勇")).
            Updates(update.Set("age", 26)).
            UpdateOne(context.Background())
        if err != nil {
            panic(err)
        }
    
        user, err := userColl.Finder().
            Filter(query.Eq("name", "陈明勇")).
            FindOne(context.Background())
        if err != nil {
            panic(err)
        }
    
        fmt.Println(user.UpdatedAt > int(now.Unix()))   // true
        fmt.Println(user.UpdateSecondTime > now.Unix()) // true
        fmt.Println(user.UpdateMilliTime > now.Unix())  // true
        fmt.Println(user.UpdateNanoTime > now.Unix())   // true
    }
    
    // 示例代码,仅供参考
    func newMongoClient() (*mongo.Client, error) {
        client, err := mongo.Connect(options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(options.Credential{
            Username:   "test",
            Password:   "test",
            AuthSource: "db-test",
        }))
        if err != nil {
            return nil, err
        }
        err = client.Ping(context.Background(), readpref.Primary())
        if err != nil {
            panic(err)
        }
        return client, nil
    }
    
    

    updates 参数无需指定时间字段,也能自动填充。更新数据后,通过与 now 进行比较判断字段值是否被填充。fmt.Println 语句都输出 true,说明更新时间字段的值都已更新。
  • Upsert 操作
    package main
    
    import (
        "context"
        "fmt"
        "time"
    
        "github.com/chenmingyong0423/go-mongox/v2/builder/query"
        "github.com/chenmingyong0423/go-mongox/v2/builder/update"
    
        "go.mongodb.org/mongo-driver/v2/bson"
    
        "go.mongodb.org/mongo-driver/v2/mongo"
        "go.mongodb.org/mongo-driver/v2/mongo/options"
        "go.mongodb.org/mongo-driver/v2/mongo/readpref"
    
        "github.com/chenmingyong0423/go-mongox/v2"
    )
    
    type User struct {
        ID        bson.ObjectID `bson:"_id,omitempty" mongox:"autoID"`
        Name      string        `bson:"name"`
        Age       int           `bson:"age"`
        CreatedAt time.Time     `bson:"created_at"`
        UpdatedAt int           `bson:"updated_at"` // 使用秒级时间戳填充字段
    
        CreateSecondTime int64 `bson:"create_second_time" mongox:"autoCreateTime"`        // 使用秒级时间戳填充字段
        UpdateSecondTime int64 `bson:"update_second_time" mongox:"autoUpdateTime:second"` // 使用秒级时间戳填充字段
        CreateMilliTime  int64 `bson:"create_milli_time" mongox:"autoCreateTime:milli"`   // 使用毫秒级时间戳填充字段
        UpdateMilliTime  int64 `bson:"update_milli_time" mongox:"autoUpdateTime:milli"`   // 使用毫秒级时间戳填充字段
        CreateNanoTime   int64 `bson:"create_nano_time" mongox:"autoCreateTime:nano"`     // 使用纳秒级时间戳填充字段
        UpdateNanoTime   int64 `bson:"update_nano_time" mongox:"autoUpdateTime:nano"`     // 使用纳秒级时间戳填充字段
    }
    
    func main() {
        mongoClient, err := newMongoClient()
        if err != nil {
            panic(err)
        }
        client := mongox.NewClient(mongoClient, &mongox.Config{})
        database := client.NewDatabase("db-test")
    
        userColl := mongox.NewCollection[User](database, "users")
    
        _, err = userColl.Updater().
            Filter(query.Eq("name", "Mingyong Chen")).
            Updates(update.Set("age", 18)).
            Upsert(context.Background())
        if err != nil {
            panic(err)
        }
    
        user, err := userColl.Finder().
            Filter(query.Eq("name", "Mingyong Chen")).
            FindOne(context.Background())
        if err != nil {
            panic(err)
        }
    
        fmt.Println(!user.CreatedAt.IsZero())   // true
        fmt.Println(user.UpdatedAt != 0)        // true
        fmt.Println(user.CreateSecondTime != 0) // true
        fmt.Println(user.UpdateSecondTime != 0) // true
        fmt.Println(user.CreateMilliTime != 0)  // true
        fmt.Println(user.UpdateMilliTime != 0)  // true
        fmt.Println(user.CreateNanoTime != 0)   // true
        fmt.Println(user.UpdateNanoTime != 0)   // true
    }
    
    // 示例代码,仅供参考
    func newMongoClient() (*mongo.Client, error) {
        client, err := mongo.Connect(options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(options.Credential{
            Username:   "test",
            Password:   "test",
            AuthSource: "db-test",
        }))
        if err != nil {
            return nil, err
        }
        err = client.Ping(context.Background(), readpref.Primary())
        if err != nil {
            panic(err)
        }
        return client, nil
    }
    
    

    当触发 Upsert 操作时,无需指定字段,创建时间和更新时间字段都会被填充。fmt.Println 语句都输出 true,说明所有时间字段的值都被填充。

小结

本文详细介绍了如何使用 mongox 库,在插入和更新数据时自动填充时间字段。在定义结构体时,只要满足 字段名称和类型符合规定字段包含特定标签mongox 将会自动填充时间字段的值。

1
评论
个人信息
清空
预览
提交
陈明勇一名热爱技术、乐于分享的开发者,同时也是开源爱好者。
90文章
12分类
21标签
19评论
157点赞
96496浏览量
目录