chenmingyong0423 / go-mongox

A Go Mongo library based on the official MongoDB driver, featuring streamlined document operations, generic binding of structs to collections, built-in BSON doc builder, automated field updates, struct validation, hooks, and plugin-based programming.
https://go-mongox.dev
Apache License 2.0
127 stars 6 forks source link

关于内置 Model 的一点疑问 #45

Closed lanlin closed 1 month ago

lanlin commented 4 months ago

内置 Model => https://go-mongox.dev/model.html

文档上说:更新文档(UpdateOne、UpdateMany、UpdatesWithOperator)时,会调用DefaultUpdatedAt()方法来更新UpdatedAt字段的值

实际使用时,只有 insert 有效果。update 没有起作用

chenmingyong0423 commented 4 months ago

update 的时候,设置的 updates 文档,这个文档有内嵌 mongox.Model 文档吗?或者实现 DefaultModelHook 了吗?如果没有满足这两个条件之一,是不会触发调用 DefaultUpdatedAt()

chenmingyong0423 commented 4 months ago

update 的时候,设置的 updates 文档,这个文档有内嵌 mongox.Model 文档吗?或者实现 DefaultModelHook 了吗?如果没有满足这两个条件之一,是不会触发调用 DefaultUpdatedAt()

就是更新文档,需要实现 DefaultModelHook,才会调用 DefaultUpdatedAt(),你的更新文档如果是结构体,那么需要实现这个接口,或者内嵌 mongox.Model

lanlin commented 4 months ago
package mongox

// ------------------------------------------------------------------------------

import (
    "context"
    "github.com/chenmingyong0423/go-mongox/hook/field"
    "github.com/chenmingyong0423/go-mongox/operation"
    "github.com/stretchr/testify/assert"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "testing"
    "time"
)

// ------------------------------------------------------------------------------

type TestColl struct {
    Model     `bson:"inline"`
    TypeId    primitive.ObjectID `bson:"typeId"`
    Title     string             `bson:"title"`
    EndTime   time.Time          `bson:"endTime"`
    StartTime time.Time          `bson:"startTime"`
}

// ------------------------------------------------------------------------------

func init() {
    opTypes := []operation.OpType{
        operation.OpTypeBeforeInsert,
        operation.OpTypeBeforeUpsert,
        operation.OpTypeBeforeUpdate,
    }
    for _, opType := range opTypes {
        typ := opType
        RegisterPlugin("mongox:default_field", func(ctx context.Context, opCtx *operation.OpContext, opts ...any) error {
            return field.Execute(ctx, opCtx, typ, opts...)
        }, typ)
    }
}

// ------------------------------------------------------------------------------

func getTheCollection(t *testing.T) *mongo.Collection {
    client, _ := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(options.Credential{
        Username:   "test",
        Password:   "test",
        AuthSource: "db-test",
    }))

    return client.Database("db-test").Collection("test")
}

// ------------------------------------------------------------------------------

func TestUpdate(t *testing.T) {
    id, _ := primitive.ObjectIDFromHex("6672a64211224bf308a14394")
    fnd := bson.M{"_id": id}

    // 1
    upd := bson.M{"$set": &TestColl{
        TypeId: primitive.NewObjectID(),
    }}

    // 2
    // upd := update.Set("typeId", primitive.NewObjectID())

    // 3
    // upd := &EventColl{
    //  TypeId: primitive.NewObjectID(),
    // }

    coll := NewCollection[TestColl](getTheCollection(t))
    _, err := coll.Updater().RegisterBeforeHooks().Filter(fnd).Updates(upd).UpdateOne(context.Background(), nil)
    assert.NoError(t, err)
}

// ------------------------------------------------------------------------------

我尝试了代码中的 1-3 种方式,都不起作用

lanlin commented 4 months ago

update 的时候,设置的 updates 文档,这个文档有内嵌 mongox.Model 文档吗?或者实现 DefaultModelHook 了吗?如果没有满足这两个条件之一,是不会触发调用 DefaultUpdatedAt()

coll := NewCollection[TestColl](getTheCollection(t))

额,难道不是直接根据泛型来判断触发的吗?一般来说既然定义了 collection的 struct包含了内置的 Model, 更新的时候应该可以直接根据泛型来判断吧,还需要另外将 update 也嵌入一个 Model 吗?

chenmingyong0423 commented 4 months ago

update 的时候,设置的 updates 文档,这个文档有内嵌 mongox.Model 文档吗?或者实现 DefaultModelHook 了吗?如果没有满足这两个条件之一,是不会触发调用 DefaultUpdatedAt()

coll := NewCollection[TestColl](getTheCollection(t))

额,难道不是直接根据泛型来判断触发的吗?一般来说既然定义了 collection的 struct包含了内置的 Model, 更新的时候应该可以直接根据泛型来判断吧,还需要另外将 update 也嵌入一个 Model 吗?

我明白你的意思,你的意思是,绑定的泛型参数有内置 Model,那么就应该根据这个判断是否去调用 DefaultUpdatedAt()

不过目前的设计,是基于 updates 这个函数的参数去判断的,也就是你传进来的 updates 文档对象,这个对象如果满足条件(内嵌 mongox.Model 或实现 DefaultModelHook 接口),才会去调用 DefaultUpdatedAt()

泛型参数,是用于查询操作,做映射的,更新操作暂时没用到。

你的这个问题确实值得思考,看起来这样实现会更好,而不是依赖 updates

lanlin commented 4 months ago

好的,谢谢你的解释。

个人感觉可以考虑直接根据泛型来判断。

主要是mongodb的update太灵活了,很多种写法,根据updates来判断估计会比较麻烦。

另外就是根据updates的话可能侵入性也比较大。

毕竟更新可能就发生在很多不同的字段组合,这个时候还要每个组合额外去定义一个包含内嵌Model的struct的话,好像有点得不偿失。

个人的一点浅见,仅供参考

这个库写的非常棒,加油!

chenmingyong0423 commented 4 months ago

好的,谢谢你的解释。

个人感觉可以考虑直接根据泛型来判断。

主要是mongodb的update太灵活了,很多种写法,根据updates来判断估计会比较麻烦。

另外就是根据updates的话可能侵入性也比较大。

毕竟更新可能就发生在很多不同的字段组合,这个时候还要每个组合额外去定义一个包含内嵌Model的struct的话,好像有点得不偿失。

个人的一点浅见,仅供参考

这个库写的非常棒,加油!

嗯嗯,感谢你的建议,如果没有使用泛型的情况下,一般根据 updates 判断,有了泛型,确实是根据泛型判断是最好的。

chenmingyong0423 commented 4 months ago

不过通过泛型去判断会有一些问题:

chenmingyong0423 commented 1 month ago

@lanlin 已经重构了设计,最新版本已经确保所有相关字段都被正确初始化或更新。

最新文档可参考 内置 Model