 
 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.