Lets start by heading to https://start.spring.io/ and creating our project.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
package com.example.demo;
import lombok.Data;
@Data
public class Person {
private String name;
private int age;
}
Getters, Setters, ToString, EqualsAndHashCode and No Args Constructor methods are all automatically set up for the above class.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
spring.data.mongodb.database=demo
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
This is all we need to do to establish the database connection. Spring Boot will handle the rest.
package com.example.demo.Beans;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
// Lombok's data annotation
@Data
// Spring will create MongoDB collection/table
@Document
public class Person {
// Table id
@Id
private String id;
// A unique index for email field will be created
@Indexed(unique = true)
private String email;
private String name;
private int age;
}
package com.example.demo.Controllers;
import com.example.demo.Beans.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/person")
public class PersonController {
@Autowired
private MongoTemplate mongoTemplate;
// POST http://localhost:8080/person
@PostMapping
public ResponseEntity savePerson(@RequestBody Person person) {
mongoTemplate.save(person);
return ResponseEntity.ok("OK");
}
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)
2019-03-23 09:52:01.680 INFO 5410 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on enes with PID 5410 (/Users/enes/Downloads/demo/target/classes started by enes in /Users/enes/Downloads/demo)
2019-03-23 09:52:01.683 INFO 5410 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2019-03-23 09:52:02.557 INFO 5410 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-03-23 09:52:02.579 INFO 5410 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 17ms. Found 0 repository interfaces.
2019-03-23 09:52:03.401 INFO 5410 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-03-23 09:52:03.466 INFO 5410 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-03-23 09:52:03.466 INFO 5410 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.16]
2019-03-23 09:52:03.508 INFO 5410 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/enes/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2019-03-23 09:52:03.871 INFO 5410 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-03-23 09:52:03.871 INFO 5410 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2093 ms
2019-03-23 09:52:04.343 INFO 5410 --- [ main] org.mongodb.driver.cluster : Cluster created with settings {hosts=[localhost:27017], mode=MULTIPLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2019-03-23 09:52:04.344 INFO 5410 --- [ main] org.mongodb.driver.cluster : Adding discovered server localhost:27017 to client view of cluster
2019-03-23 09:52:04.411 INFO 5410 --- [localhost:27017] org.mongodb.driver.connection : Opened connection [connectionId{localValue:1, serverValue:35}] to localhost:27017
2019-03-23 09:52:04.416 INFO 5410 --- [localhost:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=localhost:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[4, 0, 4]}, minWireVersion=0, maxWireVersion=7, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=3021897}
2019-03-23 09:52:04.417 INFO 5410 --- [localhost:27017] org.mongodb.driver.cluster : Discovered cluster type of STANDALONE
2019-03-23 09:52:04.678 INFO 5410 --- [ main] org.mongodb.driver.connection : Opened connection [connectionId{localValue:2, serverValue:36}] to localhost:27017
2019-03-23 09:52:05.004 INFO 5410 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-03-23 09:52:05.262 INFO 5410 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-03-23 09:52:05.268 INFO 5410 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 4.409 seconds (JVM running for 5.554)
You'll notice that the MongoDB connection is automagically established for us.
Using Robo 3T check the records.
Now that we have a couple records, we can make some queries.
package com.example.demo.Controllers;
import com.example.demo.Beans.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/person")
public class PersonController {
@Autowired
private MongoTemplate mongoTemplate;
// POST http://localhost:8080/person
@PostMapping
public ResponseEntity savePerson(@RequestBody Person person) {
mongoTemplate.save(person);
return ResponseEntity.ok("OK");
}
// Get all person records
// GET http://localhost:8080/person
@GetMapping
public ResponseEntity getAllRecords() {
List<Person> people = mongoTemplate.findAll(Person.class);
return ResponseEntity.ok(people);
}
// Find by email
// GET http://localhost:8080/person/[email protected]
@GetMapping("/email")
public ResponseEntity findByEmail(@RequestParam("email") String email) {
Query query = new Query();
query.addCriteria(Criteria.where("email").is(email));
Person person = mongoTemplate.findOne(query, Person.class);
return ResponseEntity.ok(person);
}
// Find by email containing text
// GET http://localhost:8080/person/emailContaining?email=demo
@GetMapping("/emailContaining")
public ResponseEntity emailContains(@RequestParam("email") String email) {
Query query = new Query();
query.addCriteria(Criteria.where("email").regex(email));
List<Person> people = mongoTemplate.find(query, Person.class);
return ResponseEntity.ok(people);
}
// Find by age greater than
// GET http://localhost:8080/person/age?ageGreaterThan=27
@GetMapping("/age")
public ResponseEntity findByAge(@RequestParam("ageGreaterThan") int age) {
Query query = new Query();
query.addCriteria(Criteria.where("age").gt(age));
List<Person> people = mongoTemplate.find(query, Person.class);
return ResponseEntity.ok(people);
}
// Find by age between
// GET http://localhost:8080/person/ageBetween?age1=25&age2=27
@GetMapping("/ageBetween")
public ResponseEntity findByAgeBetween(@RequestParam("age1") int age1,
@RequestParam("age2") int age2) {
Query query = new Query();
query.addCriteria(Criteria.where("age").gt(age1).lt(age2));
List<Person> people = mongoTemplate.find(query, Person.class);
return ResponseEntity.ok(people);
}
}
PageRequest.of()'s page starts with 0. So first page is 0.
// Page and sort
// GET http://localhost:8080/person/pageAndSort?page=0&size=3
@GetMapping("/pageAndSort")
public ResponseEntity pageAndSort(@RequestParam("page") int page, @RequestParam("size") int size) {
Query query = new Query();
Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "age");
query.with(pageable);
List<Person> people = mongoTemplate.find(query, Person.class);
return ResponseEntity.ok(people);
}
Use the following method to check if your queries are using an index.
// import org.bson.Document;
public String explainQuery(Query query, String collectionName) {
MongoCollection<Document> collection = mongoTemplate.getCollection(collectionName);
FindIterable<Document> result = collection.find(query.getQueryObject()).modifiers(new Document("$explain", true));
return result.first().toJson();
}
// Find by email
@GetMapping("/email")
public ResponseEntity findByEmail(@RequestParam("email") String email) {
Query query = new Query();
query.addCriteria(Criteria.where("email").is(email));
String explainResult = explainQuery(query, "person");
System.out.println(explainResult);
Person person = mongoTemplate.findOne(query, Person.class);
return ResponseEntity.ok(person);
}
If the explain result contains "stage" : "IXSCAN" then the index is being used.
That's all for now. Have a nice day.