Deep Dive into Spring Data and MongoDB Fabiano Guizellini Modos Software Architect at HBSIS @fmodos
I Java and MongoDB
Why do I love Java? Learned Object Oriented • Programming Design Patterns, Clean Code, Unit Test • Saved me from Programming in • Delphi
Why do I love MongoDB? Save complex Objects in an easy way • No more relational database • commands: Create table, Alter Table, etc.. Open Source •
It is not only a Story ...run this in Production in 3 critical systems
~5k Suppliers Invoice Daily Order ~4M Events Daily >10M DB Ops/Daily Validate Suppliers Invoice Invoice >100k Sales Invoices Daily Order Supermarket >500k Events Daily Sales Invoice >10M DB Ops/Daily Invoice Supermarket ~35k Transport Invoice Daily Transport Invoice ~300k Events Daily Deliver >1M DB Ops/Daily
Why did we use MongoDB? Complex documents and events • High Concurrency System •
Why did we use MongoDB? Complex documents and events • High Concurrency System •
Relational Database? SQL? SQL NOSQL
“Different databases are designed to solve different problems. Using a single database engine for all of the requirements usually leads to non- performant solutions” ― Pramod J. Sadalage, NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence “Complex applications combine different types of problems, so picking the right language for each job may be more productive than trying to fit all aspects into a single language.” ― Pramod J. Sadalage, NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence
Case Study – Food Recipe System Users should be able to create Dish with a name, description and list of ingredientes • Users should be able to add Comments to the Dish. • Class Diagram Table Diagram (SQL) Document Diagram (NoSQL)
Create SQL NoSQL INSERT INTO dish ( name ) db.getCollection (‘ Dish ’). save({name : “White Rice” VALUES ( “White Rice” ) ingredients : [“rice”, “ garlic ”], comments : Array[ INSERT INTO ingredient ( name, dish_id ) { VALUES ( “rice”, 1 ) text : ‘ This rice is really good ’ user : { INSERT INTO ingredient ( name ) nickname : ‘ FoodLover ’, VALUES ( “garlic”, 1 ) email: ‘fabiano@mail.com’ } INSERT INTO comment ( text, user_id, dish_id ) ] VALUES ( “This rice is really good”, 1, 1 ) })
Read SQL NoSQL SELECT d.name, d.description FROM dish d WHERE id=1 db.getCollection (‘ Dish ’). find({_id : 1}) SELECT i.name FROM ingredient i WHERE i.dish_id=1 SELECT c.text, u.nickname, u.name FROM comment c, user u WHERE c.user_id = u.id and c.dish_id = 1
Update SQL NoSQL UPDATE user SET nickname = ‘Bryan’ WHERE id=1 db.getCollection (‘ User ’). update({_id : 1}, {$set : {nickname : ‘Bryan’}}) {name: “White Rice” ingredients : [“rice”, “ garlic ”], comments : Array[ { Data Inconsistency text : ‘ This rice is really good ’ user : { nickname : ‘ FoodLover ’, email : ‘fabiano@mail.com’ } ]
Delete SQL NoSQL DELETE FROM ingredient WHERE dish_id=1 db.getCollection (‘ Dish ’).remove({_id : 1}) DELETE FROM comment WHERE dish_id =1 DELETE FROM dish WHERE id=1
Java MongoDB Driver
Where is the Framework to Map Java Objects and Documents? Spring Data
Spring Data “This is an umbrella project which contains many subprojects that are specific to a given database” • MongoDB • Neo4j • Cassandra • JDBC Extensions • Redis • Etc
How do we get started? • Add this maven configuration to the pom.xml file <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data- mongodb</artifactId> <version>1.10.6.RELEASE</version> </dependency> • Add the MongoDB config properties to the config file spring.data.mongodb.host=localhost spring.data.mongodb.port=27017 spring.data.mongodb.database=dish-db
Application Layers
Application Layers DishController DishService DishMongoRepository
How to create MongoDB Repository? package com.fmodos.dish.infraestructure.mongodb; import org.springframework.data.mongodb.repository.MongoRepository; import com.fmodos.dish.domain.Dish; public interface DishMongoRepository extends MongoRepository<Dish, String> { }
How to use the MongoDB Repository? @Service public class DishService { @Autowired DishMongoRepository dishRepository; public void insert(Dish dish) { dishRepository.insert(dish); Where is the insert } method? public interface DishMongoRepository extends MongoRepository<Dish, String> { }
SpringData Repositories Repository CrudRepository <extends> PagingAndSortingRepository MongoRepository DishMongoRepository
SpringData Repositories List<Dish> listDish = new ArrayList<Dish>(); <S extends T> S save(S entity); List<Dish> savedList = dishMongoRepository.save(listDish); <S extends T> Iterable<S> save(Iterable<S> entities); long count(); long count = dishMongoRepository.count(); void delete(ID id); dishMongoRepository.delete("id"); void delete(T entity); void delete(Iterable<? extends T> entities); void deleteAll();
SpringData Repositories T findOne(ID id); Dish dish = dishRepository.findOne(id) boolean exists(ID id); List<Dish> listDish = dishRepository.findAll() Iterable<T> findAll(); Iterable<T> findAll(Iterable<ID> ids); Page<Dish> pageDish = dishMongoRepository.findAll( new PageRequest(1, 10)); Iterable<T> findAll(Sort sort); Page<T> findAll(Pageable pageable);
What about Query Filter? public interface DishMongoRepository extends MongoRepository<Dish, String> { public List<Dish> findBy Name (String name); public List<Dish> findBy Name And DateCreated GreaterThan(String name Date dateCreated); } “ Methods should have verb or verb phrase names ” Clean Code
What is the magic? DSL – Dynamic Reception • Handle messages without defining them in the receiving class • Build dynamic queries using the method declaration
Spring Data Query Keyword Sample Logical result After findByBirthdateAfter(Date date) {"birthdate" : {"$gt" : date}} GreaterThan findByAgeGreaterThan(int age) {"age" : {"$gt" : age}} GreaterThanEqual findByAgeGreaterThanEqual(int {"age" : {"$gte" : age}} age) Before findByBirthdateBefore(Date date) {"birthdate" : {"$lt" : date}} LessThan findByAgeLessThan(int age) {"age" : {"$lt" : age}} LessThanEqual findByAgeLessThanEqual(int age) {"age" : {"$lte" : age}} Between findByAgeBetween(int from, int to) {"age" : {"$gt" : from, "$lt" : to}} {"age" : {"$in" : [ages…]}} In findByAgeIn(Collection ages) {"age" : {"$nin" : [ages…]}} NotIn findByAgeNotIn(Collection ages) IsNotNull, NotNull findByFirstnameNotNull() {"firstname" : {"$ne" : null}} IsNull, Null findByFirstnameNull() {"firstname" : null} Like, StartingWith, EndingWith findByFirstnameLike(String name) {"firstname" : name} (name as regex) NotLike, IsNotLike findByFirstnameNotLike(String {"firstname" : { "$not" : name }} name) (name as regex)
Spring Data Query Containing on String findByFirstnameContaining(String {"firstname" : name} (name as regex) name) NotContaining on String findByFirstnameNotContaining(String {"firstname" : { "$not" : name}} (name name) as regex) Containing on Collection findByAddressesContaining(Address {"addresses" : { "$in" : address}} address) NotContaining on Collection findByAddressesNotContaining(Addr {"addresses" : { "$not" : { "$in" : ess address) address}}} Regex findByFirstnameRegex(String {"firstname" : {"$regex" : firstname }} firstname) (No keyword) findByFirstname(String name) {"firstname" : name} Not findByFirstnameNot(String name) {"firstname" : {"$ne" : name}} IsTrue, True findByActiveIsTrue() {"active" : true} IsFalse, False findByActiveIsFalse() {"active" : false} Exists findByLocationExists(boolean exists) {"location" : {"$exists" : exists }}
MongoDB JSON Based Query public interface DishMongoRepository extends MongoRepository<Dish, String> { @Query(value="{ 'ingredients' : {$in : ?0 }", fields="{ 'name' : 1}") public List<Dish> findNameByIngredients(List<String> ingredients); }
Recommend
More recommend