Deep Dive into Spring Data and MongoDB Fabiano Guizellini Modos - - PowerPoint PPT Presentation

deep dive into spring data and mongodb
SMART_READER_LITE
LIVE PREVIEW

Deep Dive into Spring Data and MongoDB Fabiano Guizellini Modos - - PowerPoint PPT Presentation

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


slide-1
SLIDE 1

Deep Dive into Spring Data and MongoDB

Fabiano Guizellini Modos Software Architect at HBSIS @fmodos

slide-2
SLIDE 2

I Java and MongoDB

slide-3
SLIDE 3

Why do I love Java?

  • Learned Object Oriented

Programming

  • Design Patterns, Clean Code, Unit Test
  • Saved me from Programming in

Delphi

slide-4
SLIDE 4

Why do I love MongoDB?

  • Save complex Objects in an easy way
  • No more relational database

commands: Create table, Alter Table, etc..

  • Open Source
slide-5
SLIDE 5

It is not only a Story ...run this in Production in 3 critical systems

slide-6
SLIDE 6

Order Invoice

Supermarket

Order Invoice

Supermarket

Deliver ~5k Suppliers Invoice Daily ~4M Events Daily >10M DB Ops/Daily >100k Sales Invoices Daily >500k Events Daily >10M DB Ops/Daily ~35k Transport Invoice Daily ~300k Events Daily >1M DB Ops/Daily Validate Suppliers Invoice Sales Invoice Transport Invoice

slide-7
SLIDE 7

Why did we use MongoDB?

  • Complex documents and events
  • High Concurrency System
slide-8
SLIDE 8

Why did we use MongoDB?

  • Complex documents and events
  • High Concurrency System
slide-9
SLIDE 9

Relational Database? SQL?

SQL NOSQL

slide-10
SLIDE 10

“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

  • f 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

  • f Polyglot Persistence
slide-11
SLIDE 11

Case Study – Food Recipe System

Class Diagram Table Diagram (SQL) Document Diagram (NoSQL)

  • 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.
slide-12
SLIDE 12

Create

SQL NoSQL INSERT INTO dish (name) VALUES (“White Rice”) INSERT INTO ingredient (name, dish_id) VALUES (“rice”, 1) INSERT INTO ingredient (name) VALUES (“garlic”, 1) INSERT INTO comment (text, user_id, dish_id) VALUES (“This rice is really good”, 1, 1) db.getCollection(‘Dish’).save({name: “White Rice” ingredients : [“rice”, “garlic”], comments : Array[ { text : ‘This rice is really good’ user : { nickname : ‘FoodLover’, email: ‘fabiano@mail.com’ } ] })

slide-13
SLIDE 13

Read

SQL NoSQL SELECT d.name, d.description FROM dish d WHERE 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 db.getCollection(‘Dish’).find({_id : 1})

slide-14
SLIDE 14

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[ { text : ‘This rice is really good’ user : { nickname : ‘FoodLover’, email: ‘fabiano@mail.com’ } ]

Data Inconsistency

slide-15
SLIDE 15

Delete

SQL NoSQL DELETE FROM ingredient WHERE dish_id=1 DELETE FROM comment WHERE dish_id=1 DELETE FROM dish WHERE id=1 db.getCollection(‘Dish’).remove({_id : 1})

slide-16
SLIDE 16

Java MongoDB Driver

slide-17
SLIDE 17

Where is the Framework to Map Java Objects and Documents?

Spring Data

slide-18
SLIDE 18

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
slide-19
SLIDE 19

How do we get started?

  • Add this maven configuration to the pom.xml file
  • Add the MongoDB config properties to the config file

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data- mongodb</artifactId> <version>1.10.6.RELEASE</version> </dependency> spring.data.mongodb.host=localhost spring.data.mongodb.port=27017 spring.data.mongodb.database=dish-db

slide-20
SLIDE 20

Application Layers

slide-21
SLIDE 21

DishController DishService DishMongoRepository

Application Layers

slide-22
SLIDE 22

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> { }

slide-23
SLIDE 23

How to use the MongoDB Repository?

@Service public class DishService { @Autowired DishMongoRepository dishRepository; public void insert(Dish dish) { dishRepository.insert(dish); } public interface DishMongoRepository extends MongoRepository<Dish, String> { } Where is the insert method?

slide-24
SLIDE 24

SpringData Repositories

MongoRepository PagingAndSortingRepository CrudRepository Repository DishMongoRepository <extends>

slide-25
SLIDE 25

SpringData Repositories

<S extends T> S save(S entity); <S extends T> Iterable<S> save(Iterable<S> entities); long count(); void delete(ID id); void delete(T entity); void delete(Iterable<? extends T> entities); void deleteAll();

dishMongoRepository.delete("id"); List<Dish> listDish = new ArrayList<Dish>(); List<Dish> savedList = dishMongoRepository.save(listDish); long count = dishMongoRepository.count();

slide-26
SLIDE 26

SpringData Repositories

T findOne(ID id); boolean exists(ID id); Iterable<T> findAll(); Iterable<T> findAll(Iterable<ID> ids); Iterable<T> findAll(Sort sort); Page<T> findAll(Pageable pageable);

List<Dish> listDish = dishRepository.findAll() Dish dish = dishRepository.findOne(id) Page<Dish> pageDish = dishMongoRepository.findAll( new PageRequest(1, 10));

slide-27
SLIDE 27

What about Query Filter?

public interface DishMongoRepository extends MongoRepository<Dish, String> { public List<Dish> findByName(String name); public List<Dish> findByNameAndDateCreatedGreaterThan(String name Date dateCreated); } “Methods should have verb or verb phrase names” Clean Code

slide-28
SLIDE 28

What is the magic? DSL – Dynamic Reception

  • Handle messages without defining

them in the receiving class

  • Build dynamic queries using the

method declaration

slide-29
SLIDE 29

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) {"age" : {"$gte" : 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}} In findByAgeIn(Collection ages) {"age" : {"$in" : [ages…​]}} NotIn findByAgeNotIn(Collection ages) {"age" : {"$nin" : [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 name) {"firstname" : { "$not" : name }} (name as regex)

slide-30
SLIDE 30

Spring Data Query

Containing on String findByFirstnameContaining(String name) {"firstname" : name} (name as regex) NotContaining on String findByFirstnameNotContaining(String name) {"firstname" : { "$not" : name}} (name as regex) Containing on Collection findByAddressesContaining(Address address) {"addresses" : { "$in" : address}} NotContaining on Collection findByAddressesNotContaining(Addr ess address) {"addresses" : { "$not" : { "$in" : address}}} Regex findByFirstnameRegex(String firstname) {"firstname" : {"$regex" : 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 }}

slide-31
SLIDE 31

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); }

slide-32
SLIDE 32

MongoTemplate Operations

mongoTemplate.upsert(new Query(Criteria.where("name").is("Brazil Food")), Update.update("description", "Really Good Food"), Dish.class) @Autowired MongoTemplate mongoTemplate;

  • Upsert - Update or insert a new Document combining the Query and the Update values
  • Autowire MongoTemplate
  • FindAndModify – Query the Document, update it and return the Updated one

Dish dish = mongoTemplate.findAndModify(new Query(Criteria.where("name").is("Brazil Food")), Update.update("description", "Really Good Food"), Dish.class); “The design goal was to make it as easy as possible to transition between the use of the base MongoDB driver and MongoOperations”

slide-33
SLIDE 33

How to combine Repository and MongoTemplate?

interface DishMongoRepository interface MongoRepository interface IDishMongoTemplateRepository class DishMongoTemplateRepository extends extends extends

slide-34
SLIDE 34

DishController DishService DishMongoRepository

Application Layers

High Coupling Between Dish Service Businesse Rules and MongoDB

slide-35
SLIDE 35

Application Layers

DishController DishService IDishRepository MongoDishRepository JpaRepository <extends> <extends> SQLDishRepository <extends>

slide-36
SLIDE 36

Database Resilience – Circuit Breaker

IDishRepository MongoDishRepository SQLDishRepository HystrixRepository <extends>

slide-37
SLIDE 37

Demo Lessons Learned

slide-38
SLIDE 38

Application Query without Index Query without Projection

slide-39
SLIDE 39

Cool features I never used in Production

slide-40
SLIDE 40

Full Text Query

Query query = TextQuery.queryText(new TextCriteria().matching("rice")); mongoTemplate.find(query, Dish.class);

Query in the Dish Fields annotated with @TextIndexed(weight=1)

Similar behavior would be to query using OR operator

slide-41
SLIDE 41

GeoSpatial – Query Player within Box

Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404)); List<Player> venues = template.find(new Query(Criteria.where("location").withinBox(box)), Player.class); class Player { private double[] location; }

slide-42
SLIDE 42

GeoSpatial – Query by distance

Point location = new Point(-73.99171, 40.738868); NearQuery query = NearQuery.near(location).maxDistance(new Distance(10, Metrics.MILES)); GeoResults<SinglePerson> = operations.geoNear(query, SinglePerson.class);

slide-43
SLIDE 43

Summary

  • Document Oriented Modelling
  • Native CRUD operations in MongoDB
  • Application Layers
  • SpringData Repositories
  • SpringData Query
  • MongoTemplate Operations
  • Lessons Learned in Production
  • FullTextQuery
  • GeoSpatialQuery
slide-44
SLIDE 44

Thank you! @fmodos