diff --git a/mongo/mongo.go b/mongo/mongo.go index edc8781..b1c8609 100644 --- a/mongo/mongo.go +++ b/mongo/mongo.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "reflect" "strings" "sync" "time" @@ -471,6 +472,7 @@ func (m *MongoDB) Update(ctx context.Context, filter bson.M, update bson.M, coll // RandomSoftDelete 随机软删除个文档的 _id func (m *MongoDB) RandomSoftDelete(ctx context.Context, limit int, collection string, opts ...options.Lister[options.UpdateManyOptions]) (result *mongo.UpdateResult, err error) { + _ = opts // 步骤 1: 使用聚合管道的 $sample 操作符随机抽取5个文档的 _id pipeline := mongo.Pipeline{ // 阶段1: 为每个文档添加一个 0-1 之间的随机数字段 'random' @@ -665,7 +667,11 @@ func EntityToBson(entity interface{}) (bson.M, error) { } // EntityToBsonWithFilter 将 *entity/entity 转换为 bson.M,并可选择是否过滤空值 -// filterEmpty: 为 true 时会过滤掉空值字段(nil、空字符串、空切片、空map等) +// filterEmpty: 为 true 时会过滤掉空值字段(nil、空字符串、空切片、空map等),但保留 int 类型的 0 值 +// 支持: +// - 未传值的指针(如 *consts.AssetStatus(nil))会被过滤 +// - 传值为0的指针(如 *consts.AssetStatus(0))不会被过滤 +// - 非0的整数值不会被过滤 func EntityToBsonWithFilter(entity interface{}, filterEmpty bool) (bson.M, error) { // 第一步:判断入参是否为 nil 或无效类型 if entity == nil { @@ -686,10 +692,43 @@ func EntityToBsonWithFilter(entity interface{}, filterEmpty bool) (bson.M, error // 如果需要过滤空值 if filterEmpty { for key, value := range bsonMap { - if g.IsEmpty(value) { + // 判断是否为空值,但保留 int 类型的 0 值 + if isEmptyWithZero(value) { delete(bsonMap, key) } } } return bsonMap, nil } + +// isEmptyWithZero 判断是否为空值,但保留 int 类型的 0 值 +// 支持区分"未传值"和"传值为0"的情况: +// - *int(nil) 或 *consts.AssetStatus(nil) → 返回 true(过滤掉) +// - *int(0) 或 *consts.AssetStatus(0) → 返回 false(保留) +// - int(0) 或 consts.AssetStatus(0) → 返回 false(保留) +func isEmptyWithZero(value interface{}) bool { + // 先检查 value 是否为 nil + if value == nil { + return true + } + rv := reflect.ValueOf(value) + kind := rv.Kind() + // 处理 nil 指针 + if kind == reflect.Ptr { + if rv.IsNil() { + return true + } + // 判断时如果是指针,需要获取指向的值的类型 + kind = rv.Elem().Kind() + } + // 数字类型(int/uint/float)都保留,包括 0 值 + switch kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + return false + default: + // 其他类型使用 g.IsEmpty 判断 + return g.IsEmpty(value) + } +}