package repo import ( "box-cost/db" dm "box-cost/db/model" "box-cost/log" "context" "encoding/json" "fmt" "time" "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" ) type RepoSession struct { Ctx context.Context Client *db.MongoDB } const ( CollectionMaterial = "material" CollectionCraft = "craft" CollectionProduct = "product" CollectionSupplier = "supplier" CollectionSupplierPrice = "supplier-price" CollectionPack = "pack" CollectionProductPlan = "product-plan" CollectionBillPurchase = "bill-purchase" CollectionBillProduce = "bill-produce" CollectionBillProduct = "bill-product" // 成品采购 CollectionSupplierMatprice = "supplier-mats" CollectionSupplierCraftprice = "supplier-crafts" CollectionSupplierProductprice = "supplier-product" // 成品采购 CollectionIncrement = "increment" CollectionSignature = "signature" CollectionUsers = "users" // 更改日志记录 // CollectionLogs = "logs" CollectionRequestLogs = "request-logs" CollectionPlanTrack = "plan-track" CollectionBillHistory = "bill-history" CollectionPlanHistory = "plan-history" ) type Map map[string]interface{} type PageResult struct { List []map[string]interface{} `json:"list"` Total int64 `json:"total"` Page int64 `json:"page"` Size int64 `json:"size"` } type PageSearchOptions struct { Db string CollectName string Page int64 Size int64 Query map[string]interface{} Project []string Sort interface{} } type DocSearchOptions struct { Db string CollectName string Query Map Project []string Sort bson.M } type DocFilterOptions struct { Db string CollectName string Query Map } func NewDocSearchOptions(filter Map, project []string) *DocSearchOptions { return &DocSearchOptions{ Query: filter, Project: project, } } func RepoAddDoc(ctx *RepoSession, collectName string, doc interface{}) (string, error) { users := ctx.Client.GetCollection(collectName) result, err := users.InsertOne(ctx.Ctx, doc) if err != nil { return "", err } return result.InsertedID.(primitive.ObjectID).Hex(), nil } func RepoAddDoc1(ctx *RepoSession, collectName string, doc interface{}, recordLogReq *RecordLogReq) (string, error) { colls := ctx.Client.GetCollection(collectName) result, err := colls.InsertOne(ctx.Ctx, doc) if err != nil { return "", err } _id := result.InsertedID.(primitive.ObjectID) insertId, err := _id.Hex(), nil if !_id.IsZero() { if isShouldRecordHistoryByName(collectName) { var newData Map colls.FindOne(ctx.Ctx, bson.M{"_id": _id}).Decode(&newData) newObjByte, err := json.Marshal(newData) if err != nil { fmt.Println("记录历史失败:", err) } history := &dm.History{ Userinfo: recordLogReq.UserInfo, TargetId: insertId, Path: recordLogReq.Path, Collection: collectName, Type: recordLogReq.Type, Content: string(newObjByte), CreateTime: time.Now(), } // 订单 if isBill(collectName) { RepoAddDoc(ctx, CollectionBillHistory, history) // 计划 } else { RepoAddDoc(ctx, CollectionPlanHistory, history) } } } return insertId, nil } func RepoDbAddDoc(ctx *RepoSession, dbName string, collectName string, doc interface{}) (string, error) { users := ctx.Client.GetDbCollection(dbName, collectName) result, err := users.InsertOne(ctx.Ctx, doc) if err != nil { return "", err } return result.InsertedID.(primitive.ObjectID).Hex(), nil } func RepoDeleteDoc(ctx *RepoSession, collectName string, id string) (interface{}, error) { uid, _ := primitive.ObjectIDFromHex(id) colls := ctx.Client.GetCollection(collectName) return colls.DeleteOne(ctx.Ctx, &bson.M{"_id": uid}) } func RepoDeleteDbDoc(ctx *RepoSession, dbName string, collectName string, id string) (interface{}, error) { uid, _ := primitive.ObjectIDFromHex(id) colls := ctx.Client.GetDbCollection(dbName, collectName) return colls.DeleteOne(ctx.Ctx, &bson.M{"_id": uid}) } func RepoDeleteDocs(ctx *RepoSession, collectName string, query interface{}) (interface{}, error) { colls := ctx.Client.GetCollection(collectName) return colls.DeleteMany(ctx.Ctx, query) } func RepoUpdateSetDoc(ctx *RepoSession, collectName string, idstr string, model interface{}) (*mongo.UpdateResult, error) { colls := ctx.Client.GetCollection(collectName) update := bson.M{"$set": model} uid, _ := primitive.ObjectIDFromHex(idstr) return colls.UpdateByID(ctx.Ctx, uid, update) } type RecordLogReq struct { Path string UserInfo *dm.UserSmaple TargetId string Type string } func RepoUpdateSetDoc1(ctx *RepoSession, collectName string, idstr string, model interface{}, recordLogReq *RecordLogReq) (*mongo.UpdateResult, error) { colls := ctx.Client.GetCollection(collectName) update := bson.M{"$set": model} uid, _ := primitive.ObjectIDFromHex(idstr) // 查询更改前的数据,用于历史记录 result, err := colls.UpdateByID(ctx.Ctx, uid, update) // 更新出错或者没有更新就不进行更新日志记录 if err != nil || result.ModifiedCount == 0 { return result, err } if isShouldRecordHistoryByName(collectName) { var newData Map colls.FindOne(ctx.Ctx, bson.M{"_id": uid}).Decode(&newData) newObjByte, err := json.Marshal(newData) if err != nil { fmt.Println("记录历史失败:", err) } history := &dm.History{ Userinfo: recordLogReq.UserInfo, TargetId: recordLogReq.TargetId, Path: recordLogReq.Path, Collection: collectName, Type: recordLogReq.Type, Content: string(newObjByte), CreateTime: time.Now(), } // 订单 if isBill(collectName) { RepoAddDoc(ctx, CollectionBillHistory, history) // 计划 } else { RepoAddDoc(ctx, CollectionPlanHistory, history) } } return result, err } func isBill(collection string) bool { bills := []string{ CollectionBillPurchase, CollectionBillProduce, CollectionBillProduct, } for _, bill := range bills { if bill == collection { return true } } return false } func isShouldRecordHistoryByName(collection string) bool { shouldRecords := []string{ CollectionBillPurchase, CollectionBillProduce, CollectionBillProduct, CollectionProductPlan, } for _, sr := range shouldRecords { if sr == collection { return true } } return false } func RepoUpdateSeDbDoc(ctx *RepoSession, db string, collectName string, idstr string, model interface{}) (*mongo.UpdateResult, error) { colls := ctx.Client.GetDbCollection(db, collectName) update := bson.M{"$set": model} uid, _ := primitive.ObjectIDFromHex(idstr) return colls.UpdateByID(ctx.Ctx, uid, update) } func RepoUpdateSetDocProps(ctx *RepoSession, collectName string, idstr string, update interface{}) (*mongo.UpdateResult, error) { colls := ctx.Client.GetCollection(collectName) // update := bson.M{"$set": model} uid, _ := primitive.ObjectIDFromHex(idstr) return colls.UpdateByID(ctx.Ctx, uid, update) } func RepoUpdateSetDocsProps(ctx *RepoSession, filter *DocFilterOptions, model interface{}) (*mongo.UpdateResult, error) { colls := ctx.Client.GetCollection(filter.CollectName) if len(filter.Db) > 0 { colls = ctx.Client.GetDbCollection(filter.Db, filter.CollectName) } update := bson.M{"$set": model} filterParams := bson.M{} if len(filter.Query) > 0 { for k, v := range filter.Query { if k == "_id" { if uid, ok := v.(string); ok { docId, _ := primitive.ObjectIDFromHex(uid) filterParams["_id"] = docId continue } } filterParams[k] = v } } return colls.UpdateMany(ctx.Ctx, filterParams, update) } func RepoUpdateSetDbDocProps(ctx *RepoSession, db string, collectName string, idstr string, update interface{}) (*mongo.UpdateResult, error) { colls := ctx.Client.GetDbCollection(db, collectName) // update := bson.M{"$set": model} uid, _ := primitive.ObjectIDFromHex(idstr) return colls.UpdateByID(ctx.Ctx, uid, update) } func RepoSeachDoc(ctx *RepoSession, param *DocSearchOptions, v interface{}) (bool, error) { colls := ctx.Client.GetDbCollection(param.Db, param.CollectName) opt := &options.FindOneOptions{} if len(param.Project) > 0 { prj := bson.M{} for _, v := range param.Project { prj[v] = 1 } opt.SetProjection(prj) } if len(param.Sort) > 0 { opt.Sort = param.Sort } filter := bson.M{} if len(param.Query) > 0 { for k, v := range param.Query { if k == "_id" { if uid, ok := v.(string); ok { docId, _ := primitive.ObjectIDFromHex(uid) filter["_id"] = docId continue } } filter[k] = v } } err := colls.FindOne(ctx.Ctx, filter, opt).Decode(v) if err == mongo.ErrNoDocuments { return false, nil } if err != nil { return false, err } return true, nil } func RepoSeachDocMap(ctx *RepoSession, param *DocSearchOptions) (bool, map[string]interface{}) { ret := map[string]interface{}{} ok := true colls := ctx.Client.GetDbCollection(param.Db, param.CollectName) opt := &options.FindOneOptions{} if len(param.Project) > 0 { prj := bson.M{} for _, v := range param.Project { prj[v] = 1 } opt.SetProjection(prj) } if len(param.Sort) > 0 { opt.Sort = param.Sort } filter := bson.M{} if len(param.Query) > 0 { for k, v := range param.Query { if k == "_id" { if uid, ok := v.(string); ok { docId, _ := primitive.ObjectIDFromHex(uid) filter["_id"] = docId continue } } filter[k] = v } } ok = true err := colls.FindOne(ctx.Ctx, filter, opt).Decode(ret) if err == mongo.ErrNoDocuments { ok = false } if err != nil { ok = false } return ok, ret } // PageSearch 单表分页查询 func RepoPageSearch(ctx *RepoSession, para *PageSearchOptions) (out *PageResult, err error) { var colls *mongo.Collection if len(para.Db) > 0 { colls = ctx.Client.GetDbCollection(para.Db, para.CollectName) } else { colls = ctx.Client.GetCollection(para.CollectName) } findoptions := &options.FindOptions{} if para.Size > 0 { findoptions.SetLimit(para.Size) findoptions.SetSkip(para.Size * (para.Page - 1)) } if para.Sort != nil { findoptions.SetSort(para.Sort) } if len(para.Project) > 0 { prj := bson.M{} for _, v := range para.Project { prj[v] = 1 } findoptions.SetProjection(prj) } filter := bson.M{} if len(para.Query) > 0 { for k, v := range para.Query { if value, ok := v.(string); ok { if len(value) > 0 { filter[k] = v continue } } else if v != nil { filter[k] = v } } } cur, err := colls.Find(ctx.Ctx, filter, findoptions) out = &PageResult{ List: []map[string]interface{}{}, Total: 0, Page: para.Page, Size: para.Size, } if err != nil { return out, err } defer cur.Close(ctx.Ctx) err = cur.All(ctx.Ctx, &out.List) out.Total, _ = colls.CountDocuments(ctx.Ctx, filter) return } func RepoDbCountDoc(ctx *RepoSession, db string, collectionName string, Query Map) (int64, error) { colls := ctx.Client.GetDbCollection(db, collectionName) filter := bson.M{} if len(Query) > 0 { for k, v := range Query { if value, ok := v.(string); ok { if len(value) > 0 { filter[k] = v continue } } else { filter[k] = v } } } return colls.CountDocuments(ctx.Ctx, filter) } func RepoCountDoc(ctx *RepoSession, collectionName string, Query Map) (int64, error) { colls := ctx.Client.GetCollection(collectionName) filter := bson.M{} if len(Query) > 0 { for k, v := range Query { if value, ok := v.(string); ok { if len(value) > 0 { filter[k] = v continue } } else { filter[k] = v } } } return colls.CountDocuments(ctx.Ctx, filter) } // PageSearch 单表分页查询 func RepoDocsSearch(ctx *RepoSession, para *PageSearchOptions, out interface{}) (err error) { colls := ctx.Client.GetCollection(para.CollectName) if len(para.Db) > 0 { colls = ctx.Client.GetDbCollection(para.Db, para.CollectName) } findoptions := &options.FindOptions{} if para.Size > 0 { findoptions.SetLimit(para.Size) findoptions.SetSkip(para.Size * (para.Page - 1)) } if para.Sort != nil { findoptions.SetSort(para.Sort) } if len(para.Project) > 0 { prj := bson.M{} for _, v := range para.Project { prj[v] = 1 } findoptions.SetProjection(prj) } filter := bson.M{} if len(para.Query) > 0 { for k, v := range para.Query { if value, ok := v.(string); ok { if len(value) > 0 { filter[k] = v continue } } else { filter[k] = v } } } cur, err := colls.Find(ctx.Ctx, filter, findoptions) if err != nil { return err } defer cur.Close(ctx.Ctx) err = cur.All(ctx.Ctx, out) return } func RepoDocArrayAppend(ctx *RepoSession, collectName string, idstr string, fieldpath string, arrayItem interface{}) (*mongo.UpdateResult, error) { colls := ctx.Client.GetCollection(collectName) arrayOp := bson.M{} arrayOp[fieldpath] = arrayItem update := bson.M{"$push": arrayOp} uid, _ := primitive.ObjectIDFromHex(idstr) return colls.UpdateByID(ctx.Ctx, uid, update) } // { _id: 4, "grades.grade": 85 }, // { $set: { "grades.$.std" : 6 } } type ArrayOneUpdateOption struct { Query Map Set Map CollectName string Id string } // if len(scene.Stickers) > 0 { // optSet["scenes.$.stickers"] = scene.Stickers // } // option := &repo.ArrayOneUpdateOption{ // CollectName: repo.CollectionDesigns, // Id: id, // Query: repo.Map{"scenes.id": scene.Id}, // Set: optSet, // } func RepoDocArrayOneUpdate(ctx *RepoSession, options *ArrayOneUpdateOption) (*mongo.UpdateResult, error) { colls := ctx.Client.GetCollection(options.CollectName) docId, _ := primitive.ObjectIDFromHex(options.Id) query := bson.M{"_id": docId} if len(options.Query) > 0 { for k, v := range options.Query { query[k] = v } } setOp := bson.M{} for k, v := range options.Set { setOp[k] = v } update := bson.M{"$set": setOp} return colls.UpdateOne(ctx.Ctx, query, update) } type ArrayOneRemoveOption struct { ArrayQuery Map CollectName string Id string } // { $pull: { "items" : { id: 23 } } } func RepoDocArrayOneRemove(ctx *RepoSession, options *ArrayOneRemoveOption) (*mongo.UpdateResult, error) { colls := ctx.Client.GetCollection(options.CollectName) docId, _ := primitive.ObjectIDFromHex(options.Id) query := bson.M{"_id": docId} arrayQuery := bson.M{} if len(options.ArrayQuery) > 0 { for k, v := range options.ArrayQuery { arrayQuery[k] = v } } update := bson.M{"$pull": arrayQuery} return colls.UpdateOne(ctx.Ctx, query, update) } type ArrayOneSearchOption struct { ArrayQuery Map CollectName string Id string Field string } func RepoDocArraySearch(ctx *RepoSession, options *ArrayOneSearchOption, entity interface{}) error { colls := ctx.Client.GetCollection(options.CollectName) docId, _ := primitive.ObjectIDFromHex(options.Id) match := []bson.E{} match = append(match, bson.E{"_id", docId}) matchStage := bson.D{ {"$match", match}, } unwindStage := bson.D{ {"$unwind", fmt.Sprintf("%s%s", "$", options.Field)}, } pipe := mongo.Pipeline{matchStage, unwindStage} if len(options.ArrayQuery) > 0 { match2 := []bson.E{} for k, v := range options.ArrayQuery { match2 = append(match2, bson.E{k, v}) } match2Stage := bson.D{ {"$match", match2}, } pipe = append(pipe, match2Stage) } curr, err := colls.Aggregate(ctx.Ctx, pipe) if err != nil { return err } defer curr.Close(ctx.Ctx) if curr.Next(ctx.Ctx) { err = curr.Decode(entity) if err != nil { return err } return nil } return nil } type DocsSearchOptions struct { CollectName string Query map[string]interface{} Project []string Sort interface{} //bson.D{ bson.E{"update_time", -1}, bson.E{"goods_id", -1},} } func RepoSeachDocsMap(ctx *RepoSession, param *DocsSearchOptions) (ok bool, list []map[string]interface{}) { colls := ctx.Client.GetCollection(param.CollectName) findoptions := &options.FindOptions{} if len(param.Project) > 0 { prj := bson.M{} for _, v := range param.Project { prj[v] = 1 } findoptions.SetProjection(prj) } if param.Sort != nil { findoptions.SetSort(param.Sort) } filter := bson.M{} if len(param.Query) > 0 { for k, v := range param.Query { if value, ok := v.(string); ok { if len(value) > 0 { filter[k] = v continue } } else { filter[k] = v } } } cur, err := colls.Find(ctx.Ctx, filter, findoptions) if err != nil { ok = false return } defer cur.Close(ctx.Ctx) listRes := []map[string]interface{}{} err = cur.All(ctx.Ctx, &listRes) if err != nil { log.Error(err) ok = false return } list = listRes ok = true return } type DbDocsSearchOptions struct { Db string CollectName string Query map[string]interface{} Project []string Sort interface{} //bson.D{ bson.E{"update_time", -1}, bson.E{"goods_id", -1},} } func DbRepoSeachDocsMap(ctx *RepoSession, param *DbDocsSearchOptions) (ok bool, list []map[string]interface{}) { colls := ctx.Client.GetDbCollection(param.Db, param.CollectName) findoptions := &options.FindOptions{} if len(param.Project) > 0 { prj := bson.M{} for _, v := range param.Project { prj[v] = 1 } findoptions.SetProjection(prj) } if param.Sort != nil { findoptions.SetSort(param.Sort) } filter := bson.M{} if len(param.Query) > 0 { for k, v := range param.Query { if value, ok := v.(string); ok { if len(value) > 0 { filter[k] = v continue } } else { filter[k] = v } } } cur, err := colls.Find(ctx.Ctx, filter, findoptions) if err != nil { ok = false return } defer cur.Close(ctx.Ctx) listRes := []map[string]interface{}{} err = cur.All(ctx.Ctx, &listRes) if err != nil { log.Error(err) ok = false return } list = listRes ok = true return }