go-mongox icon indicating copy to clipboard operation
go-mongox copied to clipboard

关于内置 Model 的一点疑问

Open lanlin opened this issue 1 year ago • 8 comments

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

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

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

lanlin avatar Jun 20 '24 03:06 lanlin

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

chenmingyong0423 avatar Jun 20 '24 03:06 chenmingyong0423

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

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

chenmingyong0423 avatar Jun 20 '24 03:06 chenmingyong0423

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 avatar Jun 20 '24 03:06 lanlin

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

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

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

lanlin avatar Jun 20 '24 03:06 lanlin

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

chenmingyong0423 avatar Jun 20 '24 04:06 chenmingyong0423

好的,谢谢你的解释。

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

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

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

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

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

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

lanlin avatar Jun 20 '24 06:06 lanlin

好的,谢谢你的解释。

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

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

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

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

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

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

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

chenmingyong0423 avatar Jun 20 '24 06:06 chenmingyong0423

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

  • 之前的流程,调用 DefaultUpdatedAt() 是自动设置 updates 里面的 updated_at 的值,如果是通过泛型,你的 updates 里面没有这个属性,无法设置,就需要侵入式的在 updates 里添加 updated_at 这个 key-value
  • 用户不一定使用 updated_at 这个命名,如果通过泛型,还需要额外的一个途径去获取用户的更新时间的 field 命名。

chenmingyong0423 avatar Jun 21 '24 02:06 chenmingyong0423

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

最新文档可参考 内置 Model

chenmingyong0423 avatar Sep 10 '24 15:09 chenmingyong0423