Извлечение документов MongoDB, где все элементы массива НЕ находятся в диапазоне дат - PullRequest
0 голосов
/ 23 января 2020

Я изучаю Springboot и MongoDB.

У меня есть класс этой модели:

@Data
@Document(collection = "accommodations")
public class Accommodation {

    @Id
    private String accommodationId;
    @TextIndexed
    private String title;
    @Indexed
    private double pricePerNight;
    private int guests;
    @Indexed
    private double rating;
    private AccommodationType type;
    private String description;
    private boolean listed;
    private Address address;
    private Landlord landlord;
    private List<Image> images;
    private List<Review> reviews;
    private List<Booking> bookings;

    public Accommodation(String title, double pricePerNight, int guests, AccommodationType type, String description, Address address, Landlord landlord) {
        this.title = title;
        this.pricePerNight = pricePerNight;
        this.guests = guests;
        this.type = type;
        this.description = description;
        this.listed = true;
        this.address = address;
        this.landlord = landlord;
        this.rating = 0.0;
        this.images = new ArrayList<>();
        this.reviews = new ArrayList<>();
        this.bookings = new ArrayList<>();
    }

    public boolean isAvailableBetween(LocalDate checkin, LocalDate checkout) {
        return this.bookings
                .stream()
                .noneMatch(b -> (b.getCheckin().isBefore(checkout) || b.getCheckin().isEqual(checkout)) &&
                        (b.getCheckout().isAfter(checkin)) || b.getCheckout().isEqual(checkin));
    }

}

В настоящее время я использую метод isAvailableBetween для фильтрации мест, которые уже забронированы в определенный диапазон дат (регистрация и проверка).

Я хотел бы добиться того же с помощью запроса Mon go, но не могу понять, как.

Это то, что я До сих пор пытался (игнорировать другие фильтры в запросе):

@Repository
public interface AccommodationRepository extends MongoRepository<Accommodation, String>, QuerydslPredicateExecutor<Accommodation> {    

    @Query("{" +
            "$and: [" +
                "{listed:true}," +
                "{pricePerNight:{$lte:?0}}," +
                "{guests:{$gte:?1}}," +
                "{rating:{$gte:?2}}," +
                "{'landlord.trusted':?3}," +
                "{bookings:{$not:{$elemMatch:{checkin:{$lte:?5},checkout:{$gte:?4}}}}}" +
            "]" +
            "}")
    Page<Accommodation> findAccommodationsByFilter(Pageable pageable,
                                                   Double pricePerNight,
                                                   Integer guests,
                                                   Double rating,
                                                   Boolean trusted,
                                                   LocalDate checkin,
                                                   LocalDate checkout

}

Также пытался использовать QueryDSL & Mon go Критерии с Spring Data MongoDB, но не мог найти способ получить тот же результат, что и для isAvailableBetween.

Кто-нибудь знает, как это сделать?

1 Ответ

0 голосов
/ 25 января 2020

Изучив Пн go Критерии далее, я нашел решение!

public Page<Accommodation> findAccommodationsByFilter(AccommodationFilter filter, Pageable pageable) {

    Criteria listedTrue = where("listed").is(true);
    Query query = query(listedTrue);
    filter.pricePerNight().map(where("pricePerNight")::lte).ifPresent(query::addCriteria);
    filter.guests().map(where("guests")::gte).ifPresent(query::addCriteria);
    filter.type().map(where("type")::is).ifPresent(query::addCriteria);
    filter.rating().map(where("rating")::gte).ifPresent(query::addCriteria);
    filter.trustedLandlord().map(where("landlord.trusted")::is).ifPresent(query::addCriteria);
    filter.country().map(where("address.country")::is).ifPresent(query::addCriteria);
    filter.city().map(where("address.city")::is).ifPresent(query::addCriteria);

    if(filter.checkout().isPresent() && filter.checkin().isPresent()){
        Criteria c = where("bookings")
                .not()
                .elemMatch(where("checkin").lte(filter.checkout().get())
                        .and("checkout").gte(filter.checkin().get()));

        query.addCriteria(c);
    }

    long total = this.mongoOperations.count(query, Accommodation.class);

    query.with(pageable);
    List<Accommodation> accommodations = this.mongoOperations.find(query, Accommodation.class);

    return new PageImpl<>(accommodations, pageable, total);
}

Это достигается так же, как @Query с дополнительным преимуществом, что параметры могут быть необязательными.

...