MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Przewodnik po zapytaniach w Spring Data MongoDB

1. Przegląd

Ten samouczek skupi się na tworzeniu różnych typów zapytań w Spring Data MongoDB .

Przyjrzymy się zapytaniom o dokumenty za pomocą Query i Kryteria klasy, automatycznie generowane metody zapytań, zapytania JSON i QueryDSL.

Aby zapoznać się z konfiguracją Maven, zapoznaj się z naszym artykułem wprowadzającym.

2. Zapytanie dotyczące dokumentów

Jednym z najczęstszych sposobów wysyłania zapytań do MongoDB za pomocą Spring Data jest użycie Zapytania i Kryteria klasy, które bardzo dokładnie odzwierciedlają natywne operatory.

2.1. Jest

To jest po prostu kryterium wykorzystujące równość. Zobaczmy, jak to działa.

W poniższym przykładzie będziemy szukać użytkowników o imieniu Eric .

Spójrzmy na naszą bazę danych:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 55
    }
}

Spójrzmy teraz na kod zapytania:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List<User> users = mongoTemplate.find(query, User.class);

Zgodnie z oczekiwaniami ta logika zwraca:

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.2. Wyrażenie regularne

Bardziej elastycznym i potężnym typem zapytania jest wyrażenie regularne. Tworzy to kryterium przy użyciu MongoDB $regex który zwraca wszystkie rekordy odpowiednie dla wyrażenia regularnego dla tego pola.

Działa podobnie do startingWith i kończące się na operacje.

W tym przykładzie wyszukamy wszystkich użytkowników, których nazwy zaczynają się od A .

Oto stan bazy danych:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Teraz utwórzmy zapytanie:

Query query = new Query();
query.addCriteria(Criteria.where("name").regex("^A"));
List<User> users = mongoTemplate.find(query,User.class);

To uruchamia i zwraca 2 rekordy:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Oto kolejny szybki przykład, tym razem szukamy wszystkich użytkowników, których nazwy kończące się na c :

Query query = new Query();
query.addCriteria(Criteria.where("name").regex("c$"));
List<User> users = mongoTemplate.find(query, User.class);

Wynik będzie więc następujący:

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.3. Lt i gt

Operatory te tworzą kryterium za pomocą $lt (mniej niż) i $gt (większe niż) operatorów.

Weźmy szybki przykład, w którym szukamy wszystkich użytkowników w wieku od 20 do 50 lat.

Baza danych to:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 55
    }
}

Kod zapytania:

Query query = new Query();
query.addCriteria(Criteria.where("age").lt(50).gt(20));
List<User> users = mongoTemplate.find(query,User.class);

A wyniki dla wszystkich użytkowników w wieku powyżej 20 lat i poniżej 50 lat:

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.4. Sortuj

Sortuj służy do określenia kolejności sortowania wyników.

Poniższy przykład zwraca wszystkich użytkowników posortowanych według wieku w kolejności rosnącej.

Po pierwsze, oto istniejące dane:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Po wykonaniu sortowania :

Query query = new Query();
query.with(Sort.by(Sort.Direction.ASC, "age"));
List<User> users = mongoTemplate.find(query,User.class);

A oto wynik zapytania, ładnie posortowany według wiek :

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    }
]

2.5. Stronowalny

Spójrzmy na krótki przykład z użyciem paginacji.

Oto stan bazy danych:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Oto logika zapytania, po prostu prosząc o stronę o rozmiarze 2:

final Pageable pageableRequest = PageRequest.of(0, 2);
Query query = new Query();
query.with(pageableRequest);

A wynik, 2 dokumenty, zgodnie z oczekiwaniami:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    }
]

3. Wygenerowane metody zapytań

Teraz przyjrzyjmy się częstszemu typowi zapytań, który zwykle dostarcza Spring Data, automatycznie generowanym zapytaniom na podstawie nazw metod.

Jedyne, co musimy zrobić, aby wykorzystać tego rodzaju zapytania, to zadeklarować metodę w interfejsie repozytorium:

public interface UserRepository 
  extends MongoRepository<User, String>, QueryDslPredicateExecutor<User> {
    ...
}

3.1. FindByX

Zaczniemy od prostego zbadania zapytania typu findBy. W tym przypadku użyjemy find by name:

List<User> findByName(String name);

Podobnie jak w poprzedniej sekcji, 2.1, zapytanie będzie miało te same wyniki, znajdując wszystkich użytkowników o podanej nazwie:

List<User> users = userRepository.findByName("Eric");

3.2. Zaczynając od i kończące się na

W sekcji 2.2 omówiliśmy wyrażenie regularne na podstawie zapytania. Początki i końce są oczywiście mniej wydajne, ale mimo to całkiem przydatne, zwłaszcza jeśli nie musimy ich implementować.

Oto krótki przykład tego, jak wyglądałyby operacje:

List<User> findByNameStartingWith(String regexp);
List<User> findByNameEndingWith(String regexp);

Przykład rzeczywistego użycia tego byłby oczywiście bardzo prosty:

List<User> users = userRepository.findByNameStartingWith("A");
List<User> users = userRepository.findByNameEndingWith("c");

A wyniki są dokładnie takie same.

3.3. Między

Podobnie jak w sekcji 2.3, zwróci to wszystkich użytkowników w wieku od ageGT i ageLT:

List<User> findByAgeBetween(int ageGT, int ageLT);

Wywołanie metody spowoduje znalezienie dokładnie tych samych dokumentów:

List<User> users = userRepository.findByAgeBetween(20, 50);

3.4. Lubię i Zamów przez

Przyjrzyjmy się tym razem bardziej zaawansowanemu przykładowi, łączącemu dwa typy modyfikatorów dla wygenerowanego zapytania.

Będziemy szukać wszystkich użytkowników, których nazwy zawierają literę A, a także uporządkujemy wyniki według wieku, w porządku rosnącym:

List<User> users = userRepository.findByNameLikeOrderByAgeAsc("A");

Dla bazy danych, której użyliśmy w sekcji 2.4, wynik będzie następujący:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

4. Metody zapytań JSON

Jeśli nie możemy przedstawić zapytania za pomocą nazwy metody lub kryteriów, możemy zrobić coś na niższym poziomie, użyj @Query adnotacja .

Dzięki tej adnotacji możemy określić nieprzetworzone zapytanie jako ciąg zapytania Mongo JSON.

4.1. Znajdź przez

Zacznijmy od prostych i zobaczmy, jak przedstawilibyśmy znalezisko przez rodzaj metody po pierwsze:

@Query("{ 'name' : ?0 }")
List<User> findUsersByName(String name);

Ta metoda powinna zwracać użytkowników według nazwy. Symbol zastępczy ?0 odwołuje się do pierwszego parametru metody.

List<User> users = userRepository.findUsersByName("Eric");

4.2. $regex

Możemy również spojrzeć na zapytanie oparte na wyrażeniach regularnych, co oczywiście daje taki sam wynik jak w sekcjach 2.2 i 3.2:

@Query("{ 'name' : { $regex: ?0 } }")
List<User> findUsersByRegexpName(String regexp);

Użycie jest dokładnie takie samo:

List<User> users = userRepository.findUsersByRegexpName("^A");
List<User> users = userRepository.findUsersByRegexpName("c$");

4.3. $lt i $gt

Teraz zaimplementujmy lt i gt zapytanie:

@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List<User> findUsersByAgeBetween(int ageGT, int ageLT);

Teraz, gdy metoda ma 2 parametry, odwołujemy się do każdego z nich za pomocą indeksu w nieprzetworzonym zapytaniu, ?0 i ?1:

List<User> users = userRepository.findUsersByAgeBetween(20, 50);

5. Zapytania QueryDSL

MongoRepository ma dobre wsparcie dla projektu QueryDSL, więc możemy również tutaj wykorzystać ten ładny, bezpieczny typ API.

5.1. Zależności Maven

Najpierw upewnijmy się, że mamy poprawne zależności Maven zdefiniowane w pom:

<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-mongodb</artifactId>
    <version>4.3.1</version>
</dependency>
<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
    <version>4.3.1</version>
</dependency>

5.2. P -klasy

QueryDSL używa klas Q do tworzenia zapytań, ale ponieważ tak naprawdę nie chcemy tworzyć ich ręcznie, musimy je generować jakoś.

W tym celu użyjemy wtyczki apt-maven:

<plugin>    
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/java</outputDirectory>
                <processor>
                  org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
                </processor>
            </configuration>
        </execution>
     </executions>
</plugin>

Spójrzmy na użytkownika klasę, skupiając się w szczególności na @QueryEntity adnotacja:

@QueryEntity 
@Document
public class User {
 
    @Id
    private String id;
    private String name;
    private Integer age;
 
    // standard getters and setters
}

Po uruchomieniu procesu celu cyklu życia Maven (lub dowolnego innego celu po tym), wtyczka apt wygeneruje nowe klasy w target/generated-sources/java/{struktura twojego pakietu} :

/**
 * QUser is a Querydsl query type for User
 */
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QUser extends EntityPathBase<User> {

    private static final long serialVersionUID = ...;

    public static final QUser user = new QUser("user");

    public final NumberPath<Integer> age = createNumber("age", Integer.class);

    public final StringPath id = createString("id");

    public final StringPath name = createString("name");

    public QUser(String variable) {
        super(User.class, forVariable(variable));
    }

    public QUser(Path<? extends User> path) {
        super(path.getType(), path.getMetadata());
    }

    public QUser(PathMetadata<?> metadata) {
        super(User.class, metadata);
    }
}

To dzięki tej klasie nie musimy tworzyć naszych zapytań.

Na marginesie, jeśli używamy Eclipse, wprowadzenie tej wtyczki spowoduje wygenerowanie następującego ostrzeżenia w pom:

Maven zainstaluj działa dobrze, a QUser klasa jest generowana, ale wtyczka jest podświetlona w pom.

Szybkim rozwiązaniem jest ręczne wskazanie JDK w eclipse.ini :

...
-vm
{path_to_jdk}\jdk{your_version}\bin\javaw.exe

5.3. Nowe repozytorium

Teraz musimy faktycznie włączyć obsługę QueryDSL w naszych repozytoriach, co odbywa się po prostu przez rozszerzenie QueryDslPredicateExecutor interfejs :

public interface UserRepository extends 
  MongoRepository<User, String>, QuerydslPredicateExecutor<User>

5.4. Równanie

Po włączeniu obsługi zaimplementujmy teraz te same zapytania jak te, które zilustrowaliśmy wcześniej.

Zaczniemy od prostej równości:

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.eq("Eric");
List<User> users = (List<User>) userRepository.findAll(predicate);

5.5. Zaczynając od i EndingWith

Podobnie zaimplementujmy poprzednie zapytania i znajdźmy użytkowników o nazwach zaczynających się od A :

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.startsWith("A");
List<User> users = (List<User>) userRepository.findAll(predicate);

Oprócz końcówki c :

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.endsWith("c");
List<User> users = (List<User>) userRepository.findAll(predicate);

Wynik jest taki sam jak w sekcjach 2.2, 3.2 i 4.2.

5.6. Między

Następne zapytanie zwróci użytkowników w wieku od 20 do 50 lat, podobnie jak w poprzednich sekcjach:

QUser qUser = new QUser("user");
Predicate predicate = qUser.age.between(20, 50);
List<User> users = (List<User>) userRepository.findAll(predicate);

  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Co nowego w MongoDB 4.4

  2. Jak ustawić funkcjęKompatybilnośćWersja w MongoDB

  3. Porównanie dat w mongodb

  4. Jak utworzyć indeks o określonej nazwie w MongoDB?

  5. Mongoose i wiele baz danych w pojedynczym projekcie node.js