Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 10 additions & 47 deletions server/service/review.service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { In, Repository } from 'typeorm'
import { Repository } from 'typeorm'
import { Inject, InjectRepository, Service } from '../provider'
import { UserClubReviewEntity } from '../infra/database/entities/user-club-review.entity'
import { ClubReviewKeywordEntity } from '../infra/database/entities/club-review-keyword.entity'
import { ClubReviewKeywordCategoryEntity } from '../infra/database/entities/user-club-review-category.entity'
import { ReviewKeywordCategory } from '../../src/lib/schemas/common'
import { ClubRanking, MyReview } from '../../src/lib/schemas/clubs'
import { ClubAccessService } from './club-access.service'

@Service
export class ReviewService {
@InjectRepository(ClubReviewKeywordEntity)
private readonly clubReviewKeywordRepository: Repository<ClubReviewKeywordEntity>
@InjectRepository(ClubReviewKeywordCategoryEntity)
private readonly clubReviewKeywordCategoryRepository: Repository<ClubReviewKeywordCategoryEntity>
@InjectRepository(UserClubReviewEntity)
Expand Down Expand Up @@ -89,56 +86,22 @@ export class ReviewService {
public async getClubRankings(topk = 5): Promise<ClubRanking[]> {
const aggregated: {
club_id: string
total_reviews: string
rating: string
club_name: string
club_full_name: string
category: string
}[] = await this.userClubReviewRepository.query(`
SELECT ucr.club_id, COUNT(ucr.id) AS total_reviews, COALESCE(AVG(ucr.rating), 0) AS rating, MAX(c.name) AS club_name, MAX(c.full_name) AS club_full_name
SELECT ucr.club_id, MAX(c.name) AS club_name, MAX(c.category) AS category
FROM user_club_review ucr
JOIN club c ON ucr.club_id = c.uuid AND c.deleted_at IS NULL AND c.status = 'APPROVED'
GROUP BY club_id
GROUP BY ucr.club_id
ORDER BY COUNT(*) DESC
LIMIT ${topk}
`)
if (!aggregated.length) {
return []
}
const reviews = await this.userClubReviewRepository.findBy({
clubId: In(aggregated.map((it) => it.club_id)),
})
return Promise.all(
aggregated.map(async (it, idx) => {
const totalKeywords = reviews
.filter((r) => it.club_id === r.clubId)
.flatMap((r) => r.reviewKeywordIds)
const keywordIds = this.mostFrequent(totalKeywords, 3)
const keyword = await this.clubReviewKeywordRepository.findBy({ id: In(keywordIds) })
const keywordTitles = keywordIds
.map((it) => keyword.find((k) => k.id === it)?.title ?? '')
.filter((it) => it)
return {
clubId: it.club_id,
clubName: it.club_name,
clubFullName: it.club_full_name,
totalReviews: Number(it.total_reviews),
rating: Number(it.rating),
ranking: idx + 1,
keywords: keywordTitles,
}
}),
)
}

private mostFrequent(input: string[], topN = 3): string[] {
const frequencyMap = input.reduce((acc, cur) => {
acc[cur] = (acc[cur] ?? 0) + 1
return acc
}, {} as { [key: string]: number })
return Array.from(new Set(input))
.map((key): [string, number] => [key, frequencyMap[key]])
.sort((a, b) => b[1] - a[1])
.slice(0, topN)
.map((it) => it[0])
return aggregated.map((it, idx) => ({
clubId: it.club_id,
clubName: it.club_name,
category: it.category,
ranking: idx + 1,
}))
}
}
5 changes: 1 addition & 4 deletions src/lib/schemas/clubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ export const ClubRankingSchema = z
ranking: z.number().int(),
clubId: z.string().uuid(),
clubName: z.string(),
clubFullName: z.string(),
totalReviews: z.number().int(),
rating: z.number(),
keywords: z.array(z.string()),
category: z.string(),
})
.openapi('ClubRanking')

Expand Down
Loading