Upsert 的问题
mongox 版本
v1.2.0
问题
在使用内置model,并开启EnableDefaultFieldHook的情况下,insert是可以正常更新created_at字段,而使用Upsert 的情况,如果数据不存在是会插入一条新数据的,但并没有更新created_at到现在的时间 第一条数据没有时间,使用 Updater().Filter(query.Eq("name", node.Name)).Replacement(node).Upsert(context.Background()) 第二条数据有时间,使用 Creator().InsertOne(context.Background(), &node)
并且使用 Upsert 时,会覆盖掉原有的时间为空值,是使用上的问题吗,请指正
正常是会更新 created_at 的值的,麻烦提供一下 node 结构体的代码哈,我看看。
正常是会更新 created_at 的值的,麻烦提供一下 node 结构体的代码哈,我看看。
updated_at也是这个情况,Upsert 更新的时候并不会赋值,而是写入了一个 0001-01-01 00:00:00.000 的时间
另外在使用 UpdateOne 更新数据时,发现并不会去更新 updated_at
我在我这边测是没问题的,InsertOne 和 Upsert ,created_at 的值都有被设置。你可以再检查检查你的代码,然后必要时需要你提供你那边的所有代码看看才知道是什么问题。
另外在使用 UpdateOne 更新数据时,发现并不会去更新 updated_at
你这个问题,可以看看这个讨论 #45 ,没有满足条件的话,现在没有侵入式的修改 updated_at。
updated_at也是这个情况,Upsert 更新的时候并不会赋值,而是写入了一个 0001-01-01 00:00:00.000 的时间
可以看看这个讨论 https://github.com/chenmingyong0423/go-mongox/issues/45 ,没有满足条件的话,现在没有侵入式的修改 updated_at。
我在我这边测是没问题的,
InsertOne和Upsert,created_at的值都有被设置。你可以再检查检查你的代码,然后必要时需要你提供你那边的所有代码看看才知道是什么问题。
代码如下实际测试,created_at 为 0001-01-01 00:00:00.000
type Test struct {
mongox.Model `bson:"inline"`
Name string
Age int
}
test := Test{
Name: "test1",
Age: 12,
}
_, err := database2.NewCollection[Test]("test2").Updater().
Filter(
query.NewBuilder().
Eq("name", "test1").Build(),
).Replacement(test).Upsert(context.Background())
if err != nil {
fmt.Println(err.Error())
return
}
我在我这边测是没问题的,
InsertOne和Upsert,created_at的值都有被设置。你可以再检查检查你的代码,然后必要时需要你提供你那边的所有代码看看才知道是什么问题。代码如下实际测试,created_at 为 0001-01-01 00:00:00.000
type Test struct { mongox.Modelbson:"inline"Name string Age int } test := Test{ Name: "test1", Age: 12, } _, err := database2.NewCollection[Test]("test2").Updater(). Filter( query.NewBuilder(). Eq("name", "test1").Build(), ).Replacement(test).Upsert(context.Background()) if err != nil { fmt.Println(err.Error()) return }
全部代码给我看看吧,,部分代码看不出问题,包括是否调用 mongox.InitPlugin 初始化。
我在我这边测是没问题的,
InsertOne和Upsert,created_at的值都有被设置。你可以再检查检查你的代码,然后必要时需要你提供你那边的所有代码看看才知道是什么问题。代码如下实际测试,created_at 为 0001-01-01 00:00:00.000
type Test struct { mongox.Modelbson:"inline"Name string Age int } test := Test{ Name: "test1", Age: 12, } _, err := database2.NewCollection[Test]("test2").Updater(). Filter( query.NewBuilder(). Eq("name", "test1").Build(), ).Replacement(test).Upsert(context.Background()) if err != nil { fmt.Println(err.Error()) return }全部代码给我看看吧,,部分代码看不出问题,包括是否调用
mongox.InitPlugin初始化。
完整代码如下
package main
import (
"context"
"fmt"
"github.com/chenmingyong0423/go-mongox"
"github.com/chenmingyong0423/go-mongox/builder/query"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
)
func main() {
type Test struct {
mongox.Model `bson:"inline"`
Name string
Age int
}
test := Test{
Name: "test1",
Age: 12,
}
client, err := mongo.Connect(
context.Background(),
options.Client().
ApplyURI("mongodb://192.168.100.101:27017").
SetAuth(options.Credential{
Username: "xxx",
Password: "xxx",
}))
if err != nil {
log.Fatal(err)
return
}
collection := client.Database("xxx").Collection("test2")
_, err = mongox.NewCollection[Test](collection).Updater().
Filter(
query.NewBuilder().
Eq("name", "test1").Build(),
).Replacement(test).Upsert(context.Background())
if err != nil {
fmt.Println(err.Error())
return
}
}
我在我这边测是没问题的,
InsertOne和Upsert,created_at的值都有被设置。你可以再检查检查你的代码,然后必要时需要你提供你那边的所有代码看看才知道是什么问题。代码如下实际测试,created_at 为 0001-01-01 00:00:00.000
type Test struct { mongox.Modelbson:"inline"Name string Age int } test := Test{ Name: "test1", Age: 12, } _, err := database2.NewCollection[Test]("test2").Updater(). Filter( query.NewBuilder(). Eq("name", "test1").Build(), ).Replacement(test).Upsert(context.Background()) if err != nil { fmt.Println(err.Error()) return }全部代码给我看看吧,,部分代码看不出问题,包括是否调用
mongox.InitPlugin初始化。完整代码如下
package main import ( "context" "fmt" "github.com/chenmingyong0423/go-mongox" "github.com/chenmingyong0423/go-mongox/builder/query" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log" ) func main() { type Test struct { mongox.Model `bson:"inline"` Name string Age int } test := Test{ Name: "test1", Age: 12, } client, err := mongo.Connect( context.Background(), options.Client(). ApplyURI("mongodb://192.168.100.101:27017"). SetAuth(options.Credential{ Username: "xxx", Password: "xxx", })) if err != nil { log.Fatal(err) return } collection := client.Database("xxx").Collection("test2") _, err = mongox.NewCollection[Test](collection).Updater(). Filter( query.NewBuilder(). Eq("name", "test1").Build(), ).Replacement(test).Upsert(context.Background()) if err != nil { fmt.Println(err.Error()) return } }
没有调用 mongox.InitPlugin 打开配置
我在我这边测是没问题的,
InsertOne和Upsert,created_at的值都有被设置。你可以再检查检查你的代码,然后必要时需要你提供你那边的所有代码看看才知道是什么问题。代码如下实际测试,created_at 为 0001-01-01 00:00:00.000
type Test struct { mongox.Modelbson:"inline"Name string Age int } test := Test{ Name: "test1", Age: 12, } _, err := database2.NewCollection[Test]("test2").Updater(). Filter( query.NewBuilder(). Eq("name", "test1").Build(), ).Replacement(test).Upsert(context.Background()) if err != nil { fmt.Println(err.Error()) return }全部代码给我看看吧,,部分代码看不出问题,包括是否调用
mongox.InitPlugin初始化。完整代码如下
package main import ( "context" "fmt" "github.com/chenmingyong0423/go-mongox" "github.com/chenmingyong0423/go-mongox/builder/query" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log" ) func main() { type Test struct { mongox.Model `bson:"inline"` Name string Age int } test := Test{ Name: "test1", Age: 12, } client, err := mongo.Connect( context.Background(), options.Client(). ApplyURI("mongodb://192.168.100.101:27017"). SetAuth(options.Credential{ Username: "xxx", Password: "xxx", })) if err != nil { log.Fatal(err) return } collection := client.Database("xxx").Collection("test2") _, err = mongox.NewCollection[Test](collection).Updater(). Filter( query.NewBuilder(). Eq("name", "test1").Build(), ).Replacement(test).Upsert(context.Background()) if err != nil { fmt.Println(err.Error()) return } }test 传指针
传指针结果也是一样的,还是不会设置created_at
看看
https://go-mongox.dev/model.html
没有调用 mongox.InitPlugin 打开开关
没有调用 mongox.InitPlugin 打开开关
很抱歉,临时写了个例子遗漏了,我想我找到问题在哪里了
另外,当文档已存在时,再运行该例子,会出现以下问题, write exception: write errors: [After applying the update, the (immutable) field '_id' was found to have been altered to _id: ObjectId('66dade7959ed37a26cd57087')]
实际找到是会调用 mongox.Model 中的DefaultId导致的,对于Upsert 来说,当文档已存在的时候是否可以优化调用DefaultId的逻辑 func (m *Model) DefaultId() { if m.ID.IsZero() { m.ID = primitive.NewObjectID() } }
没有调用 mongox.InitPlugin 打开开关
很抱歉,临时写了个例子遗漏了,我想我找到问题在哪里了
另外,当文档已存在时,再运行该例子,会出现以下问题, write exception: write errors: [After applying the update, the (immutable) field '_id' was found to have been altered to _id: ObjectId('66dade7959ed37a26cd57087')]
实际找到是会调用 mongox.Model 中的DefaultId导致的,对于Upsert 来说,当文档已存在的时候是否可以优化调用DefaultId的逻辑 func (m *Model) DefaultId() { if m.ID.IsZero() { m.ID = primitive.NewObjectID() } }
其实没什么好的优化方法,因为在执行 upsert 操作之前,是没办法知道文档是否已存在的,DefautId 方法也是在 upsert 方法执行之前调用的。
要么你就自己自定义一个结构体,不要包含 ID 字段,实现更新 createdat 和 updatedat 的对应接口,mongox 就会去调用方法更新这两个字段,就不会有这个问题了。
你有好的想法也可以讨论讨论。
我考虑一下修改设计,upsert 的时候不要调用 DefaultId 方法,由 mongodb 自己去生成,当时设计的时候有遇到你这个问题,忘了当时的想法是咋样的了。
我考虑一下修改设计,upsert 的时候不要调用 DefaultId 方法,由 mongodb 自己去生成,当时设计的时候有遇到你这个问题,忘了当时的想法是咋样的了。
好的,非常感谢
我考虑一下修改设计,upsert 的时候不要调用 DefaultId 方法,由 mongodb 自己去生成,当时设计的时候有遇到你这个问题,忘了当时的想法是咋样的了。
发现实际上upsert是调用了三个函数,但created_at和updated_at也都一起调用了,我在想created_at是不是可以无需调用,可以利用SetOnInsert来写入created_at的值,这样就会使是插入的时候来写入created_at,而不会导致在更新的时候同样将created_at覆盖为了最新时间
另外,之前说的DefaultId 的问题,我目前使用的方式自定义了一个model,对_id使用 omitempty 标签,并且我删除了DefaultId 的内容,这样在使用upsert的时候就不会再出现更新时提示无法修改_id的问题,不知道是不是可以作为一个参考的方法
目前的设计对于 insert 操作没问题,但是对于更新,upsert 操作就有问题,所以我要修改一下设计,对于更新操作,我要侵入式的修改用户传来的 updates 文档,加上 updatedat 字段的更新,考虑到不一定是这个命名,所以我还会以另一种方式获取到字段名,对于 uosert 操作也是一样,侵入式修改 updates 文档,然后通过 SetOnInsert 决定要不要设置 id 和 created 字段。
你觉得怎么样?
目前的设计对于 insert 操作没问题,但是对于更新,upsert 操作就有问题,所以我要修改一下设计,对于更新操作,我要侵入式的修改用户传来的 updates 文档,加上 updatedat 字段的更新,考虑到不一定是这个命名,所以我还会以另一种方式获取到字段名,对于 uosert 操作也是一样,侵入式修改 updates 文档,然后通过 SetOnInsert 决定要不要设置 id 和 created 字段。
你觉得怎么样?
我觉得没问题,可以很好的解决现在的问题