From 25452e04b7a1c1cf4a6428883ce0fa4dc7d314ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Thu, 4 Dec 2025 17:38:34 +0800 Subject: [PATCH] =?UTF-8?q?mongodb=E5=9F=BA=E7=A1=80=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=A2=9E=E5=8A=A0redis=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- consts/redis_key.go | 7 +++ mongo/mongo.go | 135 +++++++++++++++++++++++++++++++++++++++++++- utils/utils.go | 20 +++++++ 3 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 consts/redis_key.go diff --git a/consts/redis_key.go b/consts/redis_key.go new file mode 100644 index 0000000..aef970f --- /dev/null +++ b/consts/redis_key.go @@ -0,0 +1,7 @@ +package consts + +const CleanList = "list:tenantId-%v:collection-%s:*" +const CleanCount = "count:tenantId-%v:collection-%s:*" +const List = "list:tenantId-%v:collection-%s:filter:%s:options:%s" +const Count = "count:tenantId-%v:collection-%s:filter:%s" +const One = "one:tenantId-%v:collection-%s:filter:%s:*" diff --git a/mongo/mongo.go b/mongo/mongo.go index 92f0c2a..834223c 100644 --- a/mongo/mongo.go +++ b/mongo/mongo.go @@ -2,9 +2,13 @@ package mongo import ( "context" + "errors" + "fmt" "strings" "time" + "gitee.com/red-future---jilin-g/common/consts" + "gitee.com/red-future---jilin-g/common/redis" "gitee.com/red-future---jilin-g/common/utils" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" @@ -36,23 +40,88 @@ func init() { } db = client.Database(dbName) } +func listOptionsToMap(ctx context.Context, opts ...options.Lister[options.FindOptions]) (m map[string]interface{}) { + // 输出opts参数中的值 + m = make(map[string]interface{}) + for _, opt := range opts { + var findOpts options.FindOptions + optFuncs := opt.List() + for _, fn := range optFuncs { + fn(&findOpts) + } + if findOpts.Limit != nil { + m["limit"] = *findOpts.Limit + } + if findOpts.Skip != nil { + m["skip"] = *findOpts.Skip + } + if findOpts.Sort != nil { + m["sort"] = findOpts.Sort + } + if findOpts.Projection != nil { + m["projection"] = findOpts.Projection + } + } + m = utils.OrderMap(m) + return +} +func oneOptionsToMap(ctx context.Context, opts ...options.Lister[options.FindOneOptions]) (m map[string]interface{}) { + // 输出opts参数中的值 + m = make(map[string]interface{}) + for _, opt := range opts { + var findOpts options.FindOneOptions + optFuncs := opt.List() + for _, fn := range optFuncs { + fn(&findOpts) + } + if findOpts.Skip != nil { + m["skip"] = *findOpts.Skip + } + if findOpts.Sort != nil { + m["sort"] = findOpts.Sort + } + if findOpts.Projection != nil { + m["projection"] = findOpts.Projection + } + } + m = utils.OrderMap(m) + return +} // Find 查询多条记录 func Find(ctx context.Context, filter bson.M, result interface{}, collection string, opts ...options.Lister[options.FindOptions]) (err error) { if err = utils.ValidStructPtr(result); err != nil { return } - filter["isDeleted"] = false user, err := utils.GetUserInfo(ctx) if err != nil { return } + filter["isDeleted"] = false filter["tenantId"] = user.TenantId + filterMap := utils.OrderMap(filter) + optsMap := listOptionsToMap(ctx, opts...) + redisKey := fmt.Sprintf(consts.List, user.TenantId, collection, gconv.String(filterMap), gconv.String(optsMap)) + resultStr, err := redis.RedisClient.Get(ctx, redisKey) + if err != nil { + return + } + if !g.IsEmpty(resultStr) { + err = gconv.Scan(resultStr, result) + if err != nil { + return err + } + return + } cur, err := db.Collection(collection).Find(ctx, filter, opts...) if err != nil { return } err = cur.All(ctx, result) + err = redis.RedisClient.SetEX(ctx, redisKey, result, int64(time.Hour)) + if err != nil { + return err + } return } @@ -65,17 +134,35 @@ func FindOne(ctx context.Context, filter bson.M, result interface{}, collection if err = utils.ValidStructPtr(result); err != nil { return } - filter["isDeleted"] = false user, err := utils.GetUserInfo(ctx) if err != nil { return } + filter["isDeleted"] = false filter["tenantId"] = user.TenantId + filterMap := utils.OrderMap(filter) + optsMap := oneOptionsToMap(ctx, opts...) + redisKey := fmt.Sprintf(consts.One, user.TenantId, collection, gconv.String(filterMap), gconv.String(optsMap)) + resultStr, err := redis.RedisClient.Get(ctx, redisKey) + if err != nil { + return + } + if !g.IsEmpty(resultStr) { + err = gconv.Scan(resultStr, result) + if err != nil { + return err + } + return + } cur := db.Collection(collection).FindOne(ctx, filter, opts...) err = cur.Decode(result) - if err == mongo.ErrNoDocuments { + if errors.Is(err, mongo.ErrNoDocuments) { err = nil } + err = redis.RedisClient.SetEX(ctx, redisKey, result, int64(time.Hour)) + if err != nil { + return err + } return } @@ -95,6 +182,14 @@ func Delete(ctx context.Context, filter bson.M, collection string, opts ...optio return } count = r.DeletedCount + _, err = redis.RedisClient.Del(ctx, fmt.Sprintf(consts.CleanList, user.TenantId, collection)) + if err != nil { + return + } + _, err = redis.RedisClient.Del(ctx, fmt.Sprintf(consts.CleanCount, user.TenantId, collection)) + if err != nil { + return + } return } @@ -118,6 +213,14 @@ func Update(ctx context.Context, filter bson.M, update bson.M, collection string if err != nil { return } + _, err = redis.RedisClient.Del(ctx, fmt.Sprintf(consts.CleanList, user.TenantId, collection)) + if err != nil { + return + } + _, err = redis.RedisClient.Del(ctx, fmt.Sprintf(consts.CleanCount, user.TenantId, collection)) + if err != nil { + return + } return } @@ -144,13 +247,39 @@ func Insert(ctx context.Context, documents []interface{}, collection string, opt return } ids = r.InsertedIDs + _, err = redis.RedisClient.Del(ctx, fmt.Sprintf(consts.CleanList, user.TenantId, collection)) + if err != nil { + return + } + _, err = redis.RedisClient.Del(ctx, fmt.Sprintf(consts.CleanCount, user.TenantId, collection)) + if err != nil { + return + } return } // Count 查询总数 func Count(ctx context.Context, filter bson.M, collection string) (count int64, err error) { + user, err := utils.GetUserInfo(ctx) + if err != nil { + return + } filter["isDeleted"] = false + filterMap := utils.OrderMap(filter) + redisKey := fmt.Sprintf(consts.Count, user.TenantId, collection, gconv.String(filterMap)) + resultStr, err := redis.RedisClient.Get(ctx, redisKey) + if err != nil { + return + } + if !g.IsEmpty(resultStr) { + count = gconv.Int64(resultStr) + return + } // 调用驱动的 CountDocuments,在数据库端执行的 count, err = db.Collection(collection).CountDocuments(ctx, filter) + err = redis.RedisClient.SetEX(ctx, redisKey, count, int64(time.Hour)) + if err != nil { + return + } return } diff --git a/utils/utils.go b/utils/utils.go index 78a176a..d539f81 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "reflect" + "sort" "time" "gitee.com/red-future---jilin-g/common/do" @@ -92,3 +93,22 @@ func GetUserInfo(ctx context.Context) (user do.User, err error) { user.TenantId = dataMap["tenantId"] return } +func OrderMap(m map[string]interface{}) map[string]interface{} { + // 提取所有key + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + + // 使用标准排序算法对key进行排序 + // 使用strings.Sort确保排序结果永远一致 + sort.Strings(keys) + + // 创建有序map + orderedMap := make(map[string]interface{}, len(m)) + for _, k := range keys { + orderedMap[k] = m[k] + } + + return orderedMap +}