diff --git a/src/main/kotlin/kr/lunaticbum/back/lun/model/Post.kt b/src/main/kotlin/kr/lunaticbum/back/lun/model/Post.kt index efc3e1f..3055867 100644 --- a/src/main/kotlin/kr/lunaticbum/back/lun/model/Post.kt +++ b/src/main/kotlin/kr/lunaticbum/back/lun/model/Post.kt @@ -223,7 +223,22 @@ interface PostRepository : ReactiveMongoRepository { // @org.springframework.data.mongodb.repository.Query("{ '\$and': [ { 'posting': true }, { '\$expr': { '\$gte': [ { '\$strLenCP': '\$id' }, 4 ] } } ] }") fun findAllByOrderByModifyTimeDesc(pageable: Pageable): Flux fun countByOrderByModifyTimeDesc(): Mono + @Aggregation(pipeline = [ + "{ \$sort: { modifyTime: -1 } }", + "{ \$group: { _id: { \$ifNull: [\"\$originId\", \"\$_id\"] }, post: { \$first: \"\$\$ROOT\" } } }", + "{ \$replaceRoot: { newRoot: \"\$post\" } }", + "{ \$match: { posting: true, postType: { \$ne: 'GIBBERISH' } } }", + "{ \$sort: { \"modifyTime\": -1 } }" + ]) fun findTop5ByOrderByReadCountDesc(): Flux + + @Aggregation(pipeline = [ + "{ \$sort: { modifyTime: -1 } }", + "{ \$group: { _id: { \$ifNull: [\"\$originId\", \"\$_id\"] }, post: { \$first: \"\$\$ROOT\" } } }", + "{ \$replaceRoot: { newRoot: \"\$post\" } }", + "{ \$match: { posting: true, postType: { \$ne: 'GIBBERISH' } } }", + "{ \$sort: { \"modifyTime\": -1 } }" + ]) fun findTop5ByOrderByModifyTimeDesc(): Flux fun findByPostTypeOrderByModifyTimeDesc(postType: String): Flux @@ -302,7 +317,7 @@ interface PostRepository : ReactiveMongoRepository { fun countLatestUniqueOrigin(): Mono // 헬퍼 클래스로 매핑 @Aggregation(pipeline = [ - "{ \$match: { \$or: [ { writer: ?0 }, { posting: true } ] } }", + "{ \$match: { \$and: [ { \$or: [ { writer: ?0 }, { posting: true } ] }, { 'postType': { \$ne: 'GIBBERISH' } } ] } }", "{ \$sort: { modifyTime: -1 } }", "{ \$group: { _id: { \$ifNull: [\"\$originId\", \"\$_id\"] }, post: { \$first: \"\$\$ROOT\" } } }", "{ \$replaceRoot: { newRoot: \"\$post\" } }", @@ -311,7 +326,7 @@ interface PostRepository : ReactiveMongoRepository { fun findLatestUniqueForWriterPaginated(username: String, pageable: Pageable): Flux @Aggregation(pipeline = [ - "{ \$match: { \$or: [ { writer: ?0 }, { posting: true } ] } }", + "{ \$match: { \$and: [ { \$or: [ { writer: ?0 }, { posting: true } ] }, { 'postType': { \$ne: 'GIBBERISH' } } ] } }", "{ \$group: { _id: { \$ifNull: [\"\$originId\", \"\$_id\"] } } }", "{ \$count: \"totalCount\" }" ]) @@ -319,41 +334,29 @@ interface PostRepository : ReactiveMongoRepository { /** - * [수정] posting이 true인 문서만 필터링하는 $match 단계를 추가합니다. - * [[[[[ FIXED LOGIC]]]]] + * [수정] GIBBERISH 타입을 제외하고, posting이 true인 문서만 필터링하는 $match 단계를 추가합니다. */ @Aggregation(pipeline = [ - // 1. Sort ALL posts first to find the absolute most recent version of each. "{ \$sort: { modifyTime: -1 } }", - // 2. Group by the original ID to get only the latest version. "{ \$group: { _id: { \$ifNull: [\"\$originId\", \"\$_id\"] }, post: { \$first: \"\$\$ROOT\" } } }", - // 3. Restore the post document structure. "{ \$replaceRoot: { newRoot: \"\$post\" } }", - // 4. NOW, filter this list of latest posts to show only the public ones. - "{ \$match: { posting: true } }", - // 5. Finally, sort the remaining public posts for display. + "{ \$match: { posting: true, postType: { \$ne: 'GIBBERISH' } } }", "{ \$sort: { \"modifyTime\": -1 } }" ]) - fun findLatestUniquePublishedPaginated(pageable: Pageable): Flux // 메서드 이름 변경 + fun findLatestUniquePublishedPaginated(pageable: Pageable): Flux /** * '고유 최신 글' 중 공개된 글의 총 개수를 카운트합니다. - * [수정] posting이 true인 문서만 필터링하는 $match 단계를 추가합니다. - * [[[[[FIXED LOGIC]]]]] + * [수정] GIBBERISH 타입을 제외하고, posting이 true인 문서만 필터링하는 $match 단계를 추가합니다. */ @Aggregation(pipeline = [ - // 1. Sort ALL posts. "{ \$sort: { modifyTime: -1 } }", - // 2. Group to get the latest version of each. "{ \$group: { _id: { \$ifNull: [\"\$originId\", \"\$_id\"] }, post: { \$first: \"\$\$ROOT\" } } }", - // 3. Restore the document. "{ \$replaceRoot: { newRoot: \"\$post\" } }", - // 4. Filter for public posts. - "{ \$match: { posting: true } }", - // 5. Count the final result. + "{ \$match: { posting: true, postType: { \$ne: 'GIBBERISH' } } }", "{ \$count: \"totalCount\" }" ]) - fun countLatestUniquePublished(): Mono // 메서드 이름 변경 + fun countLatestUniquePublished(): Mono fun findByWriterOrderByModifyTimeDesc(writer: String, pageable: Pageable): Flux // [신규 추가] @@ -383,6 +386,10 @@ interface PostRepository : ReactiveMongoRepository { "{ \$match: { _id: { \$ne: \"\" } } }" ]) fun findDistinctTags(): Flux // 반환 타입을 Document로 변경 + + // [신규 추가] GIBBERISH 제외하고 조회 + fun findByPostTypeNotOrderByModifyTimeDesc(postType: String, pageable: Pageable): Flux + fun countByPostTypeNot(postType: String): Mono } @@ -401,26 +408,30 @@ class PostManager( return postRepository.deleteById(postId) } - // [수정] 익명 사용자용 목록 조회 + // [수정] 익명 사용자용 목록 조회 (Aggregation 사용) fun findLatestUniquePaginated(pageable: Pageable) : Mono> { - return postRepository.findByPostingIsTrueOrderByModifyTimeDesc(pageable) + return postRepository.findLatestUniquePublishedPaginated(pageable) .collectList() } - // [수정] 익명 사용자용 글 개수 + // [수정] 익명 사용자용 글 개수 (Aggregation 사용) fun countLatestUnique(): Mono { - return postRepository.countByPostingIsTrue() + return postRepository.countLatestUniquePublished() + .map { it.totalCount } + .switchIfEmpty(Mono.just(0L)) } - // [수정] '글쓰기' 권한 사용자용 목록 조회 + // [수정] '글쓰기' 권한 사용자용 목록 조회 (Aggregation 사용) fun findLatestUniqueForWriter(username: String, pageable: Pageable) : Mono> { - return postRepository.findByPostingIsTrueOrWriterOrderByModifyTimeDesc(username, pageable) + return postRepository.findLatestUniqueForWriterPaginated(username, pageable) .collectList() } - // [수정] '글쓰기' 권한 사용자용 글 개수 + // [수정] '글쓰기' 권한 사용자용 글 개수 (Aggregation 사용) fun countLatestUniqueForWriter(username: String): Mono { - return postRepository.countByPostingIsTrueOrWriter(username) + return postRepository.countLatestUniqueForWriter(username) + .map { it.totalCount } + .switchIfEmpty(Mono.just(0L)) } // [수정] 익명 사용자용 인기글 @@ -541,11 +552,10 @@ class PostManager( /** - * 인증된 사용자를 위한 메서드 (모든 버전 조회) - * [FIX]: Change return type to Mono> and remove the blocking call. + * 인증된 사용자를 위한 메서드 (모든 버전 조회, GIBBERISH 제외) */ fun findAllVersionsPaginated(pageable :Pageable) : Mono> { - return postRepository.findAllByOrderByModifyTimeDesc(pageable) + return postRepository.findByPostTypeNotOrderByModifyTimeDesc(PostType.GIBBERISH.name, pageable) .map { post -> // 1. 제목을 UTF-8로 디코딩합니다. post.title = post.title?.let { URLDecoder.decode(it, "UTF-8") } ?: "" @@ -560,32 +570,13 @@ class PostManager( .collectList() } -// /** -// * 익명 사용자를 위한 메서드 (고유 최신 글 페이지네이션 조회) -// * [FIX]: This function should already be correct from the previous step. -// */ -// fun findLatestUniquePaginated(pageable: Pageable) : Mono> { // <-- Should already return Mono -// return postRepository.findLatestUniquePublishedPaginated(pageable) -// .collectList() -// } - /** - * 인증된 사용자가 보는 글의 총 개수 + * 인증된 사용자가 보는 글의 총 개수 (GIBBERISH 제외) */ fun countAllVersions(): Mono { - return postRepository.countByOrderByModifyTimeDesc() + return postRepository.countByPostTypeNot(PostType.GIBBERISH.name) } -// /** -// * 익명 사용자가 보는 글의 총 개수 -// */ -// fun countLatestUnique(): Mono { -// // AggregationCount(totalCount=N) 객체에서 Long 값만 추출합니다. 결과가 없으면 0L을 반환합니다. -// return postRepository.countLatestUniquePublished() -// .map { it.totalCount } -// .switchIfEmpty(Mono.just(0L)) -// } - /** * 좋아요 카운트를 1 증가시키고, JS에서 즉시 업데이트할 수 있도록 *업데이트된* 문서를 반환합니다. */ @@ -634,13 +625,10 @@ class PostManager( /** * 홈 화면은 이제 "익명 사용자용 최신 글"의 0번 페이지, 8개 아이템을 명시적으로 요청합니다. - * [FIX]: Return Mono> to match the updated callee. */ - fun find8() : Mono> { // <-- 3. Change return type to Mono> - // 홈 화면은 항상 0번 페이지의 8개 아이템을 요청합니다. + fun find8() : Mono> { val pageRequest = PageRequest.of(0, 8) // Page 0, Size 8 - // 하드코딩된 쿼리 대신, 익명사용자용 페이지네이션 메서드를 호출합니다. - return this.findLatestUniquePaginated(pageRequest) // <-- 4. This now correctly returns the Mono + return this.findLatestUniquePaginated(pageRequest) } fun save(post: Post): Mono { @@ -674,30 +662,6 @@ class PostManager( p } } - -// // [신규 추가] 익명 사용자용 인기글 -// fun getTop5UniquePublishedByViews(): Flux { -// return postRepository.findTop5UniquePublishedByReadCountDesc().map { p -> -// p.title = URLDecoder.decode(p.title, "UTF-8") -// if (p.title?.isEmpty() == true) { -// p.title = "무제(無題)" -// } -// println("${p.id} p.posting >> ${p.posting}") -// p -// } -// } - -// // [신규 추가] 익명 사용자용 최신글 -// fun getRecent5UniquePublished(): Flux { -// return postRepository.findTop5UniquePublishedByModifyTimeDesc().map { p -> -// p.title = URLDecoder.decode(p.title, "UTF-8") -// if (p.title?.isEmpty() == true) { -// p.title = "무제(無題)" -// } -// p -// } -// } - }