Skip to content

Commit

Permalink
[refactor] 좋아요한 장소 fetch join 적용
Browse files Browse the repository at this point in the history
  • Loading branch information
wndlthsk committed Nov 14, 2024
1 parent 07f6a28 commit 249cf14
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
import org.springframework.data.repository.query.Param;
import team7.inplace.likedPlace.domain.LikedPlace;

import java.util.Optional;

public interface LikedPlaceRepository extends JpaRepository<LikedPlace, Long> {

Optional<LikedPlace> findByUserIdAndPlaceId(Long userId, Long placeId);

Page<LikedPlace> findByUserIdAndIsLikedTrue(Long userId, Pageable pageable);

@Query("SELECT l.place.id FROM LikedPlace l WHERE l.user.id = :userId AND l.isLiked = true")
Set<Long> findPlaceIdsByUserIdAndIsLikedTrue(@Param("userId") Long userId);

@Query("SELECT lp FROM LikedPlace lp JOIN FETCH lp.place WHERE lp.user.id = :userId AND lp.isLiked = true")
Page<LikedPlace> findByUserIdAndIsLikedTrueWithPlace(@Param("userId") Long userId,
Pageable pageable);

}
157 changes: 80 additions & 77 deletions src/main/java/team7/inplace/place/application/PlaceService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package team7.inplace.place.application;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
Expand Down Expand Up @@ -28,9 +34,6 @@
import team7.inplace.video.domain.Video;
import team7.inplace.video.persistence.VideoRepository;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class PlaceService {
Expand All @@ -44,29 +47,29 @@ public class PlaceService {
private final LikedPlaceRepository likedPlaceRepository;

public Page<PlaceInfo> getPlacesWithinRadius(
PlacesCoordinateCommand placesCoordinateCommand,
PlacesFilterParamsCommand placesFilterParamsCommand) {
PlacesCoordinateCommand placesCoordinateCommand,
PlacesFilterParamsCommand placesFilterParamsCommand) {

// categories와 influencers 필터 처리
List<String> categoryFilters = placesFilterParamsCommand.isCategoryFilterExists()
? Arrays.stream(placesFilterParamsCommand.categories().split(",")).toList()
: null;
? Arrays.stream(placesFilterParamsCommand.categories().split(",")).toList()
: null;

List<String> influencerFilters = placesFilterParamsCommand.isInfluencerFilterExists()
? Arrays.stream(placesFilterParamsCommand.influencers().split(",")).toList()
: null;
? Arrays.stream(placesFilterParamsCommand.influencers().split(",")).toList()
: null;

// 주어진 좌표로 장소를 찾고, 해당 페이지의 결과를 가져옵니다.
Page<Place> placesPage = getPlacesByDistance(placesCoordinateCommand, categoryFilters,
influencerFilters);
influencerFilters);

// Place ID 목록 추출
List<Long> placeIds = getPlaceIds(placesPage);

// influencer 조회 => video->Map(placeId, influencerName)
List<Video> videos = videoRepository.findByPlaceIdIn(placeIds);
Map<Long, String> placeIdToInfluencerName = getMapPlaceIdToInfluencerName(
videos);
videos);

// PlaceInfo 생성
List<PlaceInfo> placeInfos = convertToPlaceInfos(placesPage, placeIdToInfluencerName);
Expand All @@ -76,52 +79,52 @@ public Page<PlaceInfo> getPlacesWithinRadius(
}

private List<PlaceInfo> convertToPlaceInfos(Page<Place> placesPage,
Map<Long, String> placeIdToInfluencerName) {
Map<Long, String> placeIdToInfluencerName) {
return placesPage.getContent().stream()
.map(place -> {
// map에서 조회되지 않은 placeId는 null로 처리
String influencerName = placeIdToInfluencerName.getOrDefault(place.getId(), null);
return PlaceInfo.of(place, influencerName, isLikedPlace(place.getId()));
})
.toList();
.map(place -> {
// map에서 조회되지 않은 placeId는 null로 처리
String influencerName = placeIdToInfluencerName.getOrDefault(place.getId(), null);
return PlaceInfo.of(place, influencerName, isLikedPlace(place.getId()));
})
.toList();
}

private Map<Long, String> getMapPlaceIdToInfluencerName(List<Video> videos) {
return videos.stream()
.collect(Collectors.toMap(
video -> video.getPlace().getId(),
video -> video.getInfluencer().getName(),
(existing, replacement) -> existing
));
.collect(Collectors.toMap(
video -> video.getPlace().getId(),
video -> video.getInfluencer().getName(),
(existing, replacement) -> existing
));
}

private List<Long> getPlaceIds(Page<Place> placesPage) {
return placesPage.getContent().stream()
.map(Place::getId)
.toList();
.map(Place::getId)
.toList();
}

private Page<Place> getPlacesByDistance(
PlacesCoordinateCommand placesCoordinateCommand,
List<String> categoryFilters,
List<String> influencerFilters
PlacesCoordinateCommand placesCoordinateCommand,
List<String> categoryFilters,
List<String> influencerFilters
) {
return placeRepository.findPlacesByDistanceAndFilters(
placesCoordinateCommand.topLeftLongitude(),
placesCoordinateCommand.topLeftLatitude(),
placesCoordinateCommand.bottomRightLongitude(),
placesCoordinateCommand.bottomRightLatitude(),
placesCoordinateCommand.longitude(),
placesCoordinateCommand.latitude(),
categoryFilters,
influencerFilters,
placesCoordinateCommand.pageable()
placesCoordinateCommand.topLeftLongitude(),
placesCoordinateCommand.topLeftLatitude(),
placesCoordinateCommand.bottomRightLongitude(),
placesCoordinateCommand.bottomRightLatitude(),
placesCoordinateCommand.longitude(),
placesCoordinateCommand.latitude(),
categoryFilters,
influencerFilters,
placesCoordinateCommand.pageable()
);
}

public PlaceDetailInfo getPlaceDetailInfo(Long placeId) {
Place place = placeRepository.findById(placeId)
.orElseThrow(() -> InplaceException.of(PlaceErrorCode.NOT_FOUND));
.orElseThrow(() -> InplaceException.of(PlaceErrorCode.NOT_FOUND));

Video video = null;
List<Video> videos = videoRepository.findByPlaceId(placeId);
Expand All @@ -135,26 +138,26 @@ public PlaceDetailInfo getPlaceDetailInfo(Long placeId) {

public List<Long> createPlaces(List<Create> placeCommands) {
var places = placeCommands.stream()
.map(command -> {
if (Objects.isNull(command)) {
return null;
}
return command.toEntity();
})
.toList();
.map(command -> {
if (Objects.isNull(command)) {
return null;
}
return command.toEntity();
})
.toList();
var nonNullPlaces = places.stream()
.filter(Objects::nonNull)
.toList();
.filter(Objects::nonNull)
.toList();
placeRepository.saveAll(nonNullPlaces);

var savedPlacesId = places.stream()
.map(place -> {
if (Objects.isNull(place)) {
return -1L;
}
return place.getId();
})
.toList();
.map(place -> {
if (Objects.isNull(place)) {
return -1L;
}
return place.getId();
})
.toList();

return savedPlacesId;
}
Expand All @@ -166,18 +169,18 @@ public void likeToPlace(PlaceLikeCommand comm) {
private void findOrCreateLikedPlace(Long placeId, boolean likes) {

Long userId = getUserId().orElseThrow(
() -> InplaceException.of(AuthorizationErrorCode.TOKEN_IS_EMPTY)
() -> InplaceException.of(AuthorizationErrorCode.TOKEN_IS_EMPTY)
);

LikedPlace likedPlace = likedPlaceRepository.findByUserIdAndPlaceId(userId, placeId)
.orElseGet(() -> {
// 존재하지 않는 경우에만 Place 조회 후 likedPlace 생성
Place place = placeRepository.findById(placeId)
.orElseThrow(() -> InplaceException.of(PlaceErrorCode.NOT_FOUND));
User user = userRepository.findById(userId)
.orElseThrow(() -> InplaceException.of(UserErrorCode.NOT_FOUND));
return new LikedPlace(user, place);
});
.orElseGet(() -> {
// 존재하지 않는 경우에만 Place 조회 후 likedPlace 생성
Place place = placeRepository.findById(placeId)
.orElseThrow(() -> InplaceException.of(PlaceErrorCode.NOT_FOUND));
User user = userRepository.findById(userId)
.orElseThrow(() -> InplaceException.of(UserErrorCode.NOT_FOUND));
return new LikedPlace(user, place);
});

likedPlace.updateLike(likes);
likedPlaceRepository.save(likedPlace);
Expand All @@ -191,9 +194,9 @@ private Optional<Long> getUserId() {

private boolean isLikedPlace(Long placeId) {
return getUserId()
.flatMap(userId -> likedPlaceRepository.findByUserIdAndPlaceId(userId, placeId))
.map(LikedPlace::isLiked)
.orElse(false);
.flatMap(userId -> likedPlaceRepository.findByUserIdAndPlaceId(userId, placeId))
.map(LikedPlace::isLiked)
.orElse(false);
}

public Long createPlace(Create placeCommand) {
Expand All @@ -204,30 +207,30 @@ public Long createPlace(Create placeCommand) {

public PlaceMessageCommand getPlaceMessageCommand(Long placeId) {
Place place = placeRepository.findById(placeId)
.orElseThrow(() -> InplaceException.of(PlaceErrorCode.NOT_FOUND));
.orElseThrow(() -> InplaceException.of(PlaceErrorCode.NOT_FOUND));

Video video = videoRepository.findByPlaceId(placeId)
.stream().findFirst().orElse(null);
.stream().findFirst().orElse(null);

Influencer influencer = (video != null) ? video.getInfluencer() : null;

return PlaceMessageCommand.of(place, influencer, video);
}

public Page<LikedPlaceInfo> getLikedPlaceInfo(Long userId, Pageable pageable) {
Page<LikedPlace> placePage = likedPlaceRepository.findByUserIdAndIsLikedTrue(userId,
pageable);
Page<LikedPlace> placePage = likedPlaceRepository.findByUserIdAndIsLikedTrueWithPlace(
userId, pageable);
List<Long> placeIds = placePage.map(likedPlace -> likedPlace.getPlace().getId()).toList();
List<Video> videos = videoRepository.findByPlaceIdIn(placeIds);
List<Video> videos = videoRepository.findByPlaceIdInWithInfluencer(placeIds);
Map<Long, String> placeIdToInfluencerName = getMapPlaceIdToInfluencerName(videos);

List<LikedPlaceInfo> likedPlaceInfos = placePage.getContent().stream()
.map(likedPlace -> {
String influencerName = placeIdToInfluencerName.getOrDefault(
likedPlace.getPlace().getId(), null);
return LikedPlaceInfo.of(likedPlace, influencerName);
})
.toList();
.map(likedPlace -> {
String influencerName = placeIdToInfluencerName.getOrDefault(
likedPlace.getPlace().getId(), null);
return LikedPlaceInfo.of(likedPlace, influencerName);
})
.toList();

return new PageImpl<>(likedPlaceInfos, pageable, placePage.getTotalElements());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package team7.inplace.video.persistence;

import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import team7.inplace.place.domain.Place;
import team7.inplace.video.domain.Video;

import java.util.List;
import java.util.Optional;

public interface VideoRepository extends JpaRepository<Video, Long> {

@Query("SELECT v FROM Video v JOIN FETCH v.place JOIN FETCH v.influencer ORDER BY v.viewCountIncrease DESC")
List<Video> findTop10ByOrderByViewCountIncreaseDesc(Pageable pageable);

Expand All @@ -23,12 +23,15 @@ public interface VideoRepository extends JpaRepository<Video, Long> {
Optional<Video> findTopByPlaceOrderByIdDesc(Place place);

@Query(
value = "SELECT v FROM Video v JOIN FETCH v.influencer WHERE v.place IS NULL",
countQuery = "SELECT COUNT(v) FROM Video v"
value = "SELECT v FROM Video v JOIN FETCH v.influencer WHERE v.place IS NULL",
countQuery = "SELECT COUNT(v) FROM Video v"
)
Page<Video> findAllByPlaceIsNull(Pageable pageable);

List<Video> findByPlaceIdIn(List<Long> placeIds);

List<Video> findByPlaceId(Long placeId);

@Query("SELECT v FROM Video v JOIN FETCH v.influencer WHERE v.place.id IN :placeIds")
List<Video> findByPlaceIdInWithInfluencer(List<Long> placeIds);
}

0 comments on commit 249cf14

Please sign in to comment.