diff --git a/src/docs/docs.go b/src/docs/docs.go index 333a547..1ccfc19 100644 --- a/src/docs/docs.go +++ b/src/docs/docs.go @@ -1292,9 +1292,6 @@ const docTemplate = `{ }, "rank": { "type": "integer" - }, - "rankChange": { - "type": "string" } } }, diff --git a/src/docs/swagger.json b/src/docs/swagger.json index a6a274d..95e3627 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -1281,9 +1281,6 @@ }, "rank": { "type": "integer" - }, - "rankChange": { - "type": "string" } } }, diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index e656f38..0c698a0 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -210,8 +210,6 @@ definitions: type: string rank: type: integer - rankChange: - type: string type: object response.RecommendFood: properties: diff --git a/src/features/food/model/entity/rankingFoodEntity.go b/src/features/food/model/entity/rankingFoodEntity.go index 3849407..cb34345 100644 --- a/src/features/food/model/entity/rankingFoodEntity.go +++ b/src/features/food/model/entity/rankingFoodEntity.go @@ -2,5 +2,6 @@ package entity type RankFoodRedis struct { FoodID string + Name string Score float64 } diff --git a/src/features/food/model/interface/IFoodRepository.go b/src/features/food/model/interface/IFoodRepository.go index 26e2ce1..8e89964 100644 --- a/src/features/food/model/interface/IFoodRepository.go +++ b/src/features/food/model/interface/IFoodRepository.go @@ -31,12 +31,8 @@ type IMetaFoodRepository interface { type IRankingFoodRepository interface { RankingTop(ctx context.Context) ([]*entity.RankFoodRedis, error) - PreviousRanking(ctx context.Context, food string) (int, error) - FindRankingTop10FoodHistories(ctx context.Context) ([]*entity.RankFoodRedis, error) + FindRankingFoodHistories(ctx context.Context) ([]*entity.RankFoodRedis, error) IncrementFoodRanking(ctx context.Context, redisKey string, foodName string, score float64) error - PreviousRankingExist(ctx context.Context) (int, error) - FindOneFoods(ctx context.Context, foodID int) (string, error) - ExpireRanking(ctx context.Context, key string) error } type IImageUploadFoodRepository interface { diff --git a/src/features/food/model/response/rankingFood.go b/src/features/food/model/response/rankingFood.go index fc326e7..ae0e996 100644 --- a/src/features/food/model/response/rankingFood.go +++ b/src/features/food/model/response/rankingFood.go @@ -5,7 +5,6 @@ type ResRankingFood struct { } type RankFood struct { - Rank int `json:"rank"` - Name string `json:"name"` - RankChange string `json:"rankChange"` + Rank int `json:"rank"` + Name string `json:"name"` } diff --git a/src/features/food/repository/rankingFoodRepository.go b/src/features/food/repository/rankingFoodRepository.go index 3fca1c2..908577d 100644 --- a/src/features/food/repository/rankingFoodRepository.go +++ b/src/features/food/repository/rankingFoodRepository.go @@ -2,14 +2,10 @@ package repository import ( "context" - "fmt" "main/features/food/model/entity" _interface "main/features/food/model/interface" "main/utils" - "main/utils/db/mysql" _redis "main/utils/db/redis" - "strconv" - "time" "github.com/redis/go-redis/v9" "gorm.io/gorm" @@ -31,8 +27,8 @@ func (g *RankingFoodRepository) RankingTop(ctx context.Context) ([]*entity.RankF result := []*entity.RankFoodRedis{} for _, z := range currentRankings { rankFood := &entity.RankFoodRedis{ - FoodID: z.Member.(string), - Score: z.Score, + Name: z.Member.(string), + Score: z.Score, } result = append(result, rankFood) } @@ -40,31 +36,17 @@ func (g *RankingFoodRepository) RankingTop(ctx context.Context) ([]*entity.RankF return result, nil } -func (g *RankingFoodRepository) PreviousRanking(ctx context.Context, food string) (int, error) { - // Get previous ranking of food - previousRank, err := _redis.Client.ZRevRank(ctx, _redis.PrevRankingKey, food).Result() - if err != nil { - if err == redis.Nil { - return _redis.NewRank, nil - } - return 0, utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(err.Error(), food), utils.ErrFromRedis) - } - - return int(previousRank), nil -} - -func (g *RankingFoodRepository) FindRankingTop10FoodHistories(ctx context.Context) ([]*entity.RankFoodRedis, error) { +func (g *RankingFoodRepository) FindRankingFoodHistories(ctx context.Context) ([]*entity.RankFoodRedis, error) { // gorm에서 food_histories 테이블에서 top 10가져오기 var results []struct { - FoodID int - Count int64 + name string + Count int64 } // SQL 쿼리 실행 err := g.GormDB.Table("food_histories"). - Select("food_id, COUNT(food_id) as count"). - Group("food_id"). + Select("name, COUNT(name) as count"). + Group("name"). Order("count DESC"). - Limit(10). Scan(&results).Error if err != nil { @@ -75,8 +57,8 @@ func (g *RankingFoodRepository) FindRankingTop10FoodHistories(ctx context.Contex topFoods := make([]*entity.RankFoodRedis, 0) for _, r := range results { topFoods = append(topFoods, &entity.RankFoodRedis{ - FoodID: strconv.Itoa(r.FoodID), - Score: float64(r.Count), + Name: r.name, + Score: float64(r.Count), }) } @@ -92,35 +74,3 @@ func (g *RankingFoodRepository) IncrementFoodRanking(ctx context.Context, redisK return nil } - -func (g *RankingFoodRepository) PreviousRankingExist(ctx context.Context) (int, error) { - // Check if previous ranking exists - previousExist, err := _redis.Client.Exists(ctx, _redis.PrevRankingKey).Result() - if err != nil { - return 0, utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(err.Error()), utils.ErrFromRedis) - } - - return int(previousExist), nil -} - -func (g *RankingFoodRepository) FindOneFoods(ctx context.Context, foodID int) (string, error) { - // Find food name by food ID - var foodName string - fmt.Println(foodID) - err := g.GormDB.WithContext(ctx).Model(&mysql.Foods{}).Select("name").Where("id = ?", foodID).First(&foodName).Error - if err != nil { - return "", utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(err.Error(), foodID), utils.ErrFromMysqlDB) - } - - return foodName, nil -} - -func (g *RankingFoodRepository) ExpireRanking(ctx context.Context, key string) error { - // Set expiration time for key - err := g.RedisClient.Expire(ctx, key, 30*time.Minute).Err() // RedisClient는 Redis 연결을 나타내는 변수입니다. - if err != nil { - return utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(err.Error(), key), utils.ErrFromRedis) - } - - return nil -} diff --git a/src/features/food/repository/selectFoodRepository.go b/src/features/food/repository/selectFoodRepository.go index bfd0598..fea0ce7 100644 --- a/src/features/food/repository/selectFoodRepository.go +++ b/src/features/food/repository/selectFoodRepository.go @@ -31,11 +31,11 @@ func (g *SelectFoodRepository) InsertOneFoodHistory(ctx context.Context, foodHis return nil } -func (g *SelectFoodRepository) IncrementFoodRanking(ctx context.Context, foodID string, score float64) error { +func (g *SelectFoodRepository) IncrementFoodRanking(ctx context.Context, name string, score float64) error { redisKey := _redis.RankingKey - _, err := g.RedisClient.ZAdd(ctx, redisKey, redis.Z{Score: score, Member: foodID}).Result() + _, err := g.RedisClient.ZIncrBy(ctx, redisKey, score, name).Result() if err != nil { - return utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(_errors.ErrServerError.Error()+err.Error(), foodID), utils.ErrFromRedis) + return utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(_errors.ErrServerError.Error()+err.Error(), name), utils.ErrFromRedis) } return nil } diff --git a/src/features/food/usecase/rankingFoodUseCase.go b/src/features/food/usecase/rankingFoodUseCase.go index 12da8cb..400f718 100644 --- a/src/features/food/usecase/rankingFoodUseCase.go +++ b/src/features/food/usecase/rankingFoodUseCase.go @@ -2,7 +2,6 @@ package usecase import ( "context" - "strconv" "main/features/food/model/entity" _interface "main/features/food/model/interface" @@ -32,38 +31,19 @@ func (d *RankingFoodUseCase) Ranking(c context.Context) (response.ResRankingFood //현재 랭킹 데이터가 비어 있다면 if len(currentRankings) == 0 { //rdb에서 데이터를 가져와 현재 랭킹에 저장을 한다. - currentRankings, err = d.Repository.FindRankingTop10FoodHistories(ctx) + currentRankings, err = d.Repository.FindRankingFoodHistories(ctx) if err != nil { return response.ResRankingFood{}, err } //현재 랭킹 레디스에 저장한다. for _, food := range currentRankings { - err := d.Repository.IncrementFoodRanking(ctx, _redis.RankingKey, food.FoodID, 1) + err := d.Repository.IncrementFoodRanking(ctx, _redis.RankingKey, food.Name, food.Score) if err != nil { return response.ResRankingFood{}, err } } } - // 이전 데이터가 비어 있다면 현재 랭킹 데이터를 저장한다. - previousExist, err := d.Repository.PreviousRankingExist(ctx) - if err != nil { - return response.ResRankingFood{}, err - } - if previousExist == 0 { - //이전 데이터가 없다면 현재 랭킹 데이터를 이전 랭킹 데이터로 저장한다. - for _, food := range currentRankings { - err := d.Repository.IncrementFoodRanking(ctx, _redis.PrevRankingKey, food.FoodID, food.Score) - if err != nil { - return response.ResRankingFood{}, err - } - } - //이전 데이터 만료시간을 설정한다. - err := d.Repository.ExpireRanking(ctx, _redis.PrevRankingKey) - if err != nil { - return response.ResRankingFood{}, err - } - } //이전 데이터가 있다면 랭킹 변동을 계산한다. res := response.ResRankingFood{} for i, food := range currentRankings { @@ -71,24 +51,9 @@ func (d *RankingFoodUseCase) Ranking(c context.Context) (response.ResRankingFood break } rank := i + 1 - previousRank, err := d.Repository.PreviousRanking(ctx, food.FoodID) - if err != nil { - return response.ResRankingFood{}, err - } - fID, _ := strconv.Atoi(food.FoodID) - foodName, err := d.Repository.FindOneFoods(ctx, fID) - if err != nil { - return response.ResRankingFood{}, err - } rankFood := response.RankFood{ Rank: rank, - Name: foodName, - } - if previousRank == _redis.NewRank { - rankFood.RankChange = "new" - } else { - rankChange := previousRank - rank - rankFood.RankChange = strconv.Itoa(rankChange) + Name: food.Name, } res.Foods = append(res.Foods, rankFood) diff --git a/src/features/food/usecase/selectFoodUseCase.go b/src/features/food/usecase/selectFoodUseCase.go index b83b754..f252b7a 100644 --- a/src/features/food/usecase/selectFoodUseCase.go +++ b/src/features/food/usecase/selectFoodUseCase.go @@ -3,7 +3,6 @@ package usecase import ( "context" "encoding/json" - "strconv" "strings" "main/features/food/model/entity" @@ -39,7 +38,7 @@ func (d *SelectFoodUseCase) Select(c context.Context, e entity.SelectFoodEntity) foodDTO.ID = foodID //디비에 저장한다. - foodHistoryDTO := CreateFoodHistoryDTO(foodID, e.UserID) + foodHistoryDTO := CreateFoodHistoryDTO(foodID, e.UserID, e.Name) if err := d.Repository.InsertOneFoodHistory(ctx, foodHistoryDTO); err != nil { return response.ResSelectFood{}, err } @@ -88,7 +87,7 @@ func (d *SelectFoodUseCase) Select(c context.Context, e entity.SelectFoodEntity) } //레디스 저장한다. - if err := d.Repository.IncrementFoodRanking(ctx, strconv.Itoa(int(foodDTO.ID)), 1); err != nil { + if err := d.Repository.IncrementFoodRanking(ctx, foodDTO.Name, 1); err != nil { return response.ResSelectFood{}, err } diff --git a/src/features/food/usecase/usecase.go b/src/features/food/usecase/usecase.go index 4e45a08..dbb24dc 100644 --- a/src/features/food/usecase/usecase.go +++ b/src/features/food/usecase/usecase.go @@ -157,10 +157,11 @@ func CreateSelectFoodDTO(entity entity.SelectFoodEntity) *mysql.Foods { Name: entity.Name, } } -func CreateFoodHistoryDTO(foodID, userID uint) *mysql.FoodHistory { +func CreateFoodHistoryDTO(foodID, userID uint, name string) *mysql.FoodHistory { return &mysql.FoodHistory{ FoodID: foodID, UserID: userID, + Name: name, } } diff --git a/src/utils/db/mysql/gormDB.go b/src/utils/db/mysql/gormDB.go index c1bd4a6..944630a 100644 --- a/src/utils/db/mysql/gormDB.go +++ b/src/utils/db/mysql/gormDB.go @@ -149,8 +149,9 @@ type Foods struct { } type FoodHistory struct { gorm.Model - UserID uint `json:"userID" gorm:"column:user_id"` - FoodID uint `json:"foodID" gorm:"column:food_id"` + UserID uint `json:"userID" gorm:"column:user_id"` + FoodID uint `json:"foodID" gorm:"column:food_id"` + Name string `json:"name" gorm:"column:name"` } type MetaTables struct { diff --git a/src/utils/db/mysql/table.sql b/src/utils/db/mysql/table.sql index 74df61e..31cad9e 100644 --- a/src/utils/db/mysql/table.sql +++ b/src/utils/db/mysql/table.sql @@ -134,6 +134,7 @@ CREATE TABLE food_histories ( deleted_at TIMESTAMP NULL DEFAULT NULL, food_id INT, user_id INT, + name varchar(255), FOREIGN KEY (food_id) REFERENCES foods(id) );