Docs Menu
Docs Home
/ / /
Java Sync Driver
/

Tutorial: Spring Data Framework Integration

In this tutorial, you can learn how to use Spring Data MongoDB with the Java driver to perform high-performance bulk inserts in a Spring Boot application.

Spring Data MongoDB is the official Spring Data ODM for MongoDB. It allows you to interact with MongoDB by using plain old Java objects (POJOs) and repository abstraction. It supports MongoDB-specific features like dynamic queries, indexing, and nested document mapping while reducing boilerplate code such as manual find() and update() calls.

Dependency injection (DI) is a core principle of the Spring Framework. It allows objects, called beans, to be created and managed by the Spring container, then injected into other beans that use them. This is distinct from typical object-oriented development where classes are responsible for initializing and constructing the objects they use.

For more information about dependency injection, see the Dependency Injection page of the Spring Framework documentation.

BulkOperations is a Spring Data MongoDB interface that contains a list of write operations that can be applied to your database. It can handle any combination of the following operations which map to similar MongoDB Java Driver operations:

  • insert

  • updateOne

  • updateMany

  • replaceOne

  • deleteOne

  • deleteMany

  • upsert

A BulkOperation can be ordered or unordered. Ordered bulk operations run operations sequentially, and if an error is detected, return with an error code. Unordered operations are run in parallel, which means they are typically faster. However, you must manually check if there were errors during the operations.

For more information about bulk operations, see the following resources:

  • BulkOperations in the Spring Framework API documentation

  • Bulk Write Operations in this guide

  • Bulk Write Operations in the MongoDB server manual

You can find the completed sample app for this tutorial in the SpringDataBulkInsert sample project GitHub repository.

Note

Imports Not Specified

The import statements required for the files in the tutorial have not been included on the page. See the GitHub repository for complete files.

Ensure you have the following components installed and set up before you start this tutorial:

Ensure that you use a Spring Data MongoDB version that is compatible with the MongoDB Java Driver and Java versions you are using. For compatibility specifications, see the Requirements page of the Spring Data MongoDB documentation, and the Compatibility page of this guide.

Note

If you used the Spring Initializr or a clone of the Spring Boot sample project to create your project, versioning compatibility has already been accounted for, and the spring-boot-starter-data-mongodb component will already be included in your pom.xml file.

Add the following dependencies to your pom.xml:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>3.2.5 </version>
</dependency>
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>2.4.3</version>
</dependency>

The datafaker dependency is used to generate a large quantity of Product objects to use in the bulk write operation.

The MongoConfig class contains the configuration for the MongoClient that will allow the Spring Data framework to interact with the MongoDB server, and sets other configuration options. For more information about configuration options, see the Specify Connection Options page of this guide.

This application uses @Configuration annotations for classes, @Bean annotations for methods, and @Value annotations for parameter conversion. These annotations allow the Spring IoC container to manage objects. For a detailed explanation of these annotations, see the following sections of the Spring Data framework guide:

Create a MongoConfig.java file and add the following configuration and template classes to set up your MongoDB connection:

@Configuration
public class MongoConfig {
@Value("${mongodb.uri}")
private String uri;
@Value("${mongodb.database}")
private String databaseName;
@Bean
public MongoClient mongo() {
ConnectionString connectionString = new ConnectionString(uri);
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(), databaseName);
}
}

Note

API vs Interface

This implementation uses the MongoTemplate API, rather than extending a Spring Data repository interface such as MongoRepository, to allow for fine-grained control over bulk operations.

Set the values of your connection string (mongodb.uri), database name (mongodb.database), and bulk operation count (documentCount) in your application.properties file:

mongodb.database=bulk
mongodb.uri=<connection string>
documentCount=25000

This tutorial uses a database named bulk, and creates 25000 documents to save. Replace the <connection string> placeholder with a connection string for your Atlas deployment. For more information, see the Create a Connection String section of this guide.

Mapping a class to a collection allows the Spring IoC container to store objects as MongoDB documents. You can use the @Document annotation to specify which collection a class maps to. For more information about mapping objects to MongoDB documents, see the Mapping Annotation Overview section of the Spring Data MongoDB documentation.

The @Id annotation in the following code indicates that the id field maps to the _id field which is used as a unique identifier in MongoDB documents. You can choose any field of any type, except arrays, to be the unique identifier. For more information, see the How the _id field is handled in the mapping layer section of the Spring Data MongoDB documentation.

Create a Product.java file to define your Product class and map it to your products collection with the following code:

@Document("products")
public class Product {
private static final Logger LOG = LoggerFactory
.getLogger(Products.class);
@Id
private String id;
private String name;
private int qty;
private double price;
private Date available;
private Date unavailable;
private String skuId;
public Product(String name, int qty, double price, Date available, Date unavailable, String skuId) {
this.name = name;
this.qty = qty;
this.price = price;
this.available = available;
this.unavailable = unavailable;
this.skuId = skuId;
}
public static Product [] RandomProducts( int count) {
Faker faker = new Faker();
Random rand = new Random();
Product [] retProds = new Product[count];
for (int i=0; i<count; ++i) {
Product p = new Product( faker.animal().name(),
1+rand.nextInt(998),
10.0+rand.nextInt(9999),
new Date(), new Date(),
faker.idNumber().valid());
retProds[i] = p;
}
return retProds;
}
// Getters and setters
}

The Product class includes a static method that generates an array of Product objects. You may also define getters and setters for each field.

The ProductRepository will manage a collection of Product objects. Your ProductRepository references the client creation methods defined in the MongoConfig class, which you annotated with @Bean. By using the @Autowired annotation with the mongoTemplate variable together with a constructor that includes mongoTemplate as an argument, the Spring container uses constructor injection to inject a mongoTemplate dependency. For more information about constructor injection, see the Constructor-based Dependency Injection section of the Spring Framework documentation.

Create a ProductRepository.java file and define your ProductRepository class to manage a collection of Product objects with the following code:

@Component
public class ProductRepository {
private static final Logger LOG = LoggerFactory
.getLogger(ProductRepository.class);
private final MongoTemplate mongoTemplate;
@Autowired
public ProductRepository(MongoTemplate mongoTemplate){
this.mongoTemplate = mongoTemplate;
}
public void updateProductQuantity(String name, int newQuantity) {
Query query = new Query(Criteria.where("name").is(name));
Update update = new Update();
update.set("quantity", newQuantity);
UpdateResult result = mongoTemplate.updateFirst(query, update, Product.class);
if(result == null)
LOG.error("No documents updated");
else
LOG.info(result.getModifiedCount() + " document(s) updated..");
}
public int bulkInsertProducts(int count) {
LOG.info("Dropping collection...");
mongoTemplate.dropCollection(Product.class);
LOG.info("Dropped!");
Instant start = Instant.now();
mongoTemplate.setWriteConcern(WriteConcern.W1.withJournal(true));
Product [] productList = Product.RandomProducts(count);
BulkOperations bulkInsertion = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, Product.class);
for (int i=0; i<productList.length; ++i)
bulkInsertion.insert(productList[i]);
BulkWriteResult bulkWriteResult = bulkInsertion.execute();
LOG.info("Bulk insert of "+bulkWriteResult.getInsertedCount()+" documents completed in "+ Duration.between(start, Instant.now()).toMillis() + " milliseconds");
return bulkWriteResult.getInsertedCount();
}
}

The bulkInsertProducts() method uses unordered bulk inserts, which can improve performance by not guaranteeing the order of operations.

The main application class triggers the ProductRepository to generate the specified number of Product objects and save them to your MongoDB database. It uses the @Autowired annotation to inject a ProductRepository, and implements logging.

Add the following code to your main class to run your application:

@SpringBootApplication
public class MyProjectName implements CommandLineRunner {
@Value("${documentCount}")
private int count;
private static final Logger LOG = LoggerFactory
.getLogger(MyProjectName.class);
@Autowired
private ProductRepository repository;
public static void main(String[] args) {
SpringApplication.run(MyProjectName.class, args);
}
@Override
public void run(String... args) throws Exception {
repository.bulkInsertProducts(count);
LOG.info("End run");
System.exit(1);
}
}

Spring Data MongoDB provides a high-level abstraction for working with MongoDB. It can simplify application architecture by supporting automatic dependency injection, which eliminates the need for manual client configuration and complex query handling. By reducing boilerplate code and supporting object-oriented data access, it can streamline data access and promote a clear separation of concerns.

For more information about the Spring Data Framework, see the following resources:

For support or to contribute to the MongoDB Community, see the MongoDB Developer Community.

Back

Third-Party Integrations

On this page