Ein Leitfaden für Abfragen in Spring Data MongoDB

1. Übersicht

Dieser Artikel konzentriert sich auf das Erstellen verschiedener Arten von Abfragen in Spring Data MongoDB .

Wir werden uns die Abfrage von Dokumenten mit zu suchen Abfrage und Kriterien Klassen, automatisch generierte Abfragemethoden, JSON - Abfragen und QueryDSL.

Informationen zum Maven-Setup finden Sie in unserem Einführungsartikel.

2. Dokumentenabfrage

Eine der gebräuchlichsten Methoden zum Abfragen von MongoDB mit Spring Data ist die Verwendung der Klassen Query und Criteria , die native Operatoren sehr genau widerspiegeln.

2.1. Ist

Dies ist einfach ein Kriterium für die Verwendung von Gleichheit - mal sehen, wie es funktioniert.

Im folgenden Beispiel suchen wir nach Benutzern mit dem Namen Eric .

Schauen wir uns unsere Datenbank an:

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

Schauen wir uns nun den Abfragecode an:

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

Diese Logik kehrt wie erwartet zurück:

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

2.2. Regex

Eine flexiblere und leistungsfähigere Art der Abfrage ist der reguläre Ausdruck. Dies erstellt ein Kriterium unter Verwendung eines MongoDB $ -Regex , der alle Datensätze zurückgibt, die für diesen Regexp für dieses Feld geeignet sind.

Es funktioniert ähnlich wie das Starten mit und Beenden mit Operationen - schauen wir uns ein Beispiel an.

Wir suchen jetzt nach allen Benutzern, deren Namen mit A beginnen .

Hier ist der Status der Datenbank:

[ { "_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 } ]

Lassen Sie uns nun die Abfrage erstellen:

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

Dies wird ausgeführt und gibt 2 Datensätze zurück:

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

Hier ist ein weiteres kurzes Beispiel, diesmal auf der Suche nach allen Benutzern, deren Namen mit c enden :

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

Das Ergebnis wird also sein:

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

2.3. Lt und gt

Diese Operatoren erstellen ein Kriterium mit dem Operator $ lt (kleiner als) und $ gt (größer als).

Schauen wir uns ein kurzes Beispiel an - wir suchen alle Benutzer im Alter zwischen 20 und 50 Jahren.

Die Datenbank lautet:

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

Dieser Abfragecode:

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

Und das Ergebnis - alle Benutzer, die älter als 20 Jahre und jünger als 50 Jahre sind:

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

2.4. Sortieren

Sortieren wird verwendet, um eine Sortierreihenfolge für die Ergebnisse anzugeben.

Im folgenden Beispiel werden alle Benutzer in aufsteigender Reihenfolge nach Alter sortiert zurückgegeben.

Erstens - hier sind die vorhandenen Daten:

[ { "_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 } ] 

Nach dem Ausführen der Sortierung :

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

And here's the result of the query – nicely sorted by age:

[ { "_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. Pageable

Let's look at a quick example using pagination.

Here's the state of the database:

[ { "_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 } ] 

Now, the query logic, simply asking for a page of size 2:

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

And the result – the 2 documents, as expected:

[ { "_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. Generated Query Methods

Let's now explore the more common type of query that Spring Data usually provides – auto-generated queries out of method names.

The only thing we need to do to leverage these kinds of queries is to declare the method on the repository interface:

public interface UserRepository extends MongoRepository, QueryDslPredicateExecutor { ... }

3.1. FindByX

We'll start simple, by exploring the findBy type of query – in this case, find by name:

List findByName(String name);

Same as in the previous section – 2.1 – the query will have the same results, finding all users with the given name:

List users = userRepository.findByName("Eric"); 

3.2. StartingWith and endingWith.

In 2.2, we explored a regex based query. Starts and ends with are of course less powerful, but nevertheless quite useful – especially if we don't have to actually implement them.

Here's a quick example of how the operations would look like:

List findByNameStartingWith(String regexp);
List findByNameEndingWith(String regexp);

The example of actually using this would, of course, be very simple:

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

And the results are exactly the same.

3.3. Between

Similar to 2.3, this will return all users with age between ageGT and ageLT:

List findByAgeBetween(int ageGT, int ageLT);

Calling the method will result in exactly the same documents being found:

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

3.4. Like and OrderBy

Let's have a look at a more advanced example this time – combining two types of modifiers for the generated query.

We're going to be looking for all users that have names containing the letter A and we're also going to order the results by age, in ascending order:

List users = userRepository.findByNameLikeOrderByAgeAsc("A"); 

For the database we used in 2.4 – the result will be:

[ { "_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. JSON Query Methods

If we can't represent a query with the help of a method name, or criteria, we can do something more low level – use the @Query annotation.

With this annotation, we can specify a raw query – as a Mongo JSON query string.

4.1. FindBy

Let's start simple and look at how we would represent a find by type of method first:

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

This method should return users by name – the placeholder ?0 references the first parameter of the method.

List users = userRepository.findUsersByName("Eric");

4.2 $regex

Let's also look at a regex driven query – which of course produces the same result as in 2.2 and 3.2:

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

The usage is also exactly the same:

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

4.3. $lt and $gt

Let's now implement the lt and gt query:

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

Now how, now that the method has 2 parameters, we're referencing each of these by index in the raw query: ?0 and ?1.

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

5. QueryDSL Queries

MongoRepository has good support for the QueryDSL project – so we can leverage that nice, type-safe API here as well.

5.1. The Maven Dependencies

First, let's make sure we have the correct Maven dependencies defined in the pom:

 com.mysema.querydsl querydsl-mongodb 4.3.1 com.mysema.querydsl querydsl-apt 4.3.1 

5.2. Q-classes

QueryDSL used Q-classes for creating queries. But, since we don't really want to create these by hand, we need to generate them somehow.

We're going to use the apt-maven-plugin to do that:

 com.mysema.maven apt-maven-plugin 1.1.3 process target/generated-sources/java org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor 

Let's look at the User class – focusing specifically at the @QueryEntity annotation:

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

After running the process goal of the Maven lifecycle (or anything another goal after that one) – the apt plugin will generate the new classes under target/generated-sources/java/{your package structure}:

/** * QUser is a Querydsl query type for User */ @Generated("com.mysema.query.codegen.EntitySerializer") public class QUser extends EntityPathBase { private static final long serialVersionUID = ...; public static final QUser user = new QUser("user"); public final NumberPath 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 path) { super(path.getType(), path.getMetadata()); } public QUser(PathMetadata metadata) { super(User.class, metadata); } }

It's with the help of this class that we're not going to be creating our queries.

As a side note – if you're using Eclipse, introducing this plugin will generate the following warning in pom:

You need to run build with JDK or have tools.jar on the classpath. If this occurs during eclipse build make sure you run eclipse under JDK as well (com.mysema.maven:apt-maven-plugin:1.1.3:process:default:generate-sources

Maven install works fine and QUser class is generated, but a plugin is highlighted in the pom.

A quick fix is to manually point to the JDK in eclipse.ini:

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

5.3. The New Repository

Now we need to actually enable QueryDSL support in our repositories – which is done by simply extending the QueryDslPredicateExecutor interface:

public interface UserRepository extends MongoRepository, QuerydslPredicateExecutor

5.4. Eq

With support enabled, let's now implement the same queries as the ones we illustrated before.

We'll start with simple equality:

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

5.5. StartingWith and EndingWith

Similarly, let's implement the previous queries – and find users with names that are starting with A:

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

And ending with c:

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

The result with same as in 2.2, 3.2 or 4.2.

5.6. Between

The next one query will return users with age between 20 and 50 – similar to the previous sections:

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

6. Conclusion

In this article, we explored the many ways we can query using Spring Data MongoDB.

It's interesting to take a step back and see just how many powerful ways we have to query MongoDB – varying from limited control all the way to full control with raw queries.

The implementation of all these examples and code snippets can be found in the GitHub project.