MongoDB – Model One-to-One, One-to-Many Relationships Embedded Documents | SpringBoot

With MongoDB, we can structure related data by embedded documents. In general, embedding gives a better performance for read operations. So in the tutorial, JavaSampleApproach will show you way to work with Embedded Documents using SpringBoot.

Related posts:
Spring JPA One to Many Relationship
SpringData MongoRepository
SpringData MongoDB GridFsTemplate to save, retrieve, delete binary files (Image, Text files)
Angular 4 + Spring Boot + MongoDB CRUD example

I. Technologies

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: 1.5.6RELEASE
– MongoDB: v3.4.1

II. MongoDB – Embedded Documents

Embedded Documents are generally known as denormalized models. It is a way to structure related data in a single document. See below diagram:

mongodb embedded document - structure

In general, we decide to design data as embedded models in case: data contains one-to-one or one-to-many relationships between entities.

With embedding data model, in general, it gives us a better performance for read operations. And we can use a single atomic read/write database operation to request and retrieve or update related data.

However, a weakness point is embedding related data in documents may lead to situations where documents grow after creation.

III. Practice

In the tutorial, we use SpringToolSuite to create a SpringBoot project for MongoDB embedded documents:

mongodb embedded document - springboot project structure

Step to do:
– Create SpringBoot project
– Create Document models
– Create MongoRepository
– Run and check results
– Implement Client

1. Create SpringBoot project

Using Spring Tool Suite, create a SpringBoot project. Then open pom.xml file, add dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <version>1.5.4.RELEASE</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

2. Create Document models

Create 3 class models {Company, Product, Contact} with one-to-one relationship (between Company & Contact),
and one-to-many relationship (between Company & Product) in embedded data model structure.

Company


package com.javasampleapproach.datamongodb.model;

import java.util.List;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

@Document(collection="company")
public class Company {
	@Id
	private int id;
    private String name;
    
    private List products;
    
    private Contact contact;
    
    public void setId(int id){
    	this.id = id;
    }
    
    public int getId(){
    	return this.id;
    }
    
    public void setName(String name){
    	this.name = name;
    }
    
    public String getName(){
    	return this.name;
    }
    
    public void setProducts(List products){
    	this.products = products;
    }
    
    public List getProducts(){
    	return this.products;
    }
    
    public void setContact(Contact contact){
    	this.contact = contact;
    }
    
    public Contact getContact(){
    	return this.contact;
    }
    
    public Company(int id, String name, List products, Contact contact){
    	this.id = id;
    	this.name = name;
    	this.products = products;
    	this.contact = contact;
    }
    
    @Override
    public String toString() {
    	ObjectMapper mapper = new ObjectMapper();
    	
    	String jsonString = "";
		try {
			mapper.enable(SerializationFeature.INDENT_OUTPUT);
			jsonString = mapper.writeValueAsString(this);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
		
    	return jsonString;
    }
}

Contact:


package com.javasampleapproach.datamongodb.model;

public class Contact {
	private String address;
	private String phone;
	
	public Contact(String address, String phone){
		this.address = address;
		this.phone = phone;
	}
	
	public void setAddress(String address){
		this.address = address;
	}
	
	public String getAddress(){
		return this.address;
	}
	
	public void setPhone(String phone){
		this.phone = phone;
	}
	
	public String getPhone(){
		return this.phone;
	}
}

Product:


package com.javasampleapproach.datamongodb.model;

public class Product {
	private String code;
	private String name;
	private String details;
	
	public Product(String code, String name, String details){
		this.code = code;
		this.name = name;
		this.details = details;
	}
	
	public void setCode(String code){
		this.code = code;
	}
	
	public String getCode(){
		return this.code;
	}
	
	public void setName(String name){
		this.name = name;
	}
	
	public String getName(){
		return this.name;
	}
	
	public void setDetails(String details){
		this.details = details;
	}
	
	public String getDetails(){
		return this.details;
	}
}

3. Create MongoRepository

interface CompanyRepository extends MongoRepository


package com.javasampleapproach.datamongodb.repository;

import java.util.List;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

import com.javasampleapproach.datamongodb.model.Company;

public interface CompanyRepository extends MongoRepository{
	List findByName(String name);
	
	@Query("{'contact.address': ?0}")
	List findByAddress(String address);
}

– Open application.properties, add configuration to connect with Mongo Server:


spring.data.mongodb.database=jsa_mongodb
spring.data.mongodb.port=27017

4. Implement Client

Use CommandLineRunner to implement a simple client to manipulate data from MongoDB via CompanyRepository:


package com.javasampleapproach.datamongodb;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.javasampleapproach.datamongodb.model.Company;
import com.javasampleapproach.datamongodb.model.Contact;
import com.javasampleapproach.datamongodb.model.Product;
import com.javasampleapproach.datamongodb.repository.CompanyRepository;

@SpringBootApplication
public class SpringDataMongoDbApplication implements CommandLineRunner{

	@Autowired
	CompanyRepository companyRepo;
	
	@Override
	public void run(String... args) throws Exception {
		// clear database
		System.out.println("==========Delete all company entities==========");
		companyRepo.deleteAll();
		
		// save Documents to MongoDB
		System.out.println("==========Save list of company entities==========");
		companyRepo.save(Arrays.asList(
				// Apple company & products
				new Company(1, "Apple",
						
						        // list of products
								Arrays.asList(new Product("A-123", "Iphone 7", "Price: 649.00 USD & FREE shipping"),
													  new Product("A-456", "IPadPro", "Price: 417.67 USD & FREE shipping")),
								
								// contact
								new Contact("Cupertino, CA 95014", "1-408-996-1010")),
				
				// Samsung company & products
				new Company(2, "Samsung",
						
						       // list of products
						       Arrays.asList(new Product("S-012", "GalaxyJ7", "Price: 219.00 USD & FREE shipping"),
														new Product("S-456", "GalaxyTabA", "Price: 299.99 USD & FREE shipping")),
						       
						       // contact
						       new Contact("Seocho District, Seoul, South Korea", "+82-2-2053-3000"))));
		// initial List Companies variable
		List companies = null;
		
		// fetch all documents
		System.out.println("==========Fetch aLL companies:==========");
		companies = companyRepo.findAll();
		companies.forEach(System.out::println);
		
		// find Company by name
		System.out.println("==========Find a company by name:==========");
		companies = companyRepo.findByName("Samsung");
		companies.forEach(System.out::println);
		
		// find Company by address
		System.out.println("==========Find a company by address:==========");
		companies = companyRepo.findByAddress("Cupertino, CA 95014");
		companies.forEach(System.out::println);
	}
	
	public static void main(String[] args) {
		SpringApplication.run(SpringDataMongoDbApplication.class, args);
	}
}

5. Run and check results

Start MongoDB server by commandline: .\MongoDB\Server\3.4\bin>mongod.exe

-> Logs:


2017-08-18T16:52:34.225+0700 I CONTROL  [initandlisten]
2017-08-18T16:52:35.518+0700 I FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory 'C:/data/db/diagnostic.data'
2017-08-18T16:52:35.519+0700 I NETWORK  [thread1] waiting for connections on port 27017

Build and Run the SpringBoot project with commandlines: mvn clean install, mvn spring-boot:run

-> Logs:


==========Delete all company entities==========
==========Save list of company entities==========
==========Fetch aLL companies:==========
{
  "id" : 1,
  "name" : "Apple",
  "products" : [ {
    "code" : "A-123",
    "name" : "Iphone 7",
    "details" : "Price: 649.00 USD & FREE shipping"
  }, {
    "code" : "A-456",
    "name" : "IPadPro",
    "details" : "Price: 417.67 USD & FREE shipping"
  } ],
  "contact" : {
    "address" : "Cupertino, CA 95014",
    "phone" : "1-408-996-1010"
  }
}
{
  "id" : 2,
  "name" : "Samsung",
  "products" : [ {
    "code" : "S-012",
    "name" : "GalaxyJ7",
    "details" : "Price: 219.00 USD & FREE shipping"
  }, {
    "code" : "S-456",
    "name" : "GalaxyTabA",
    "details" : "Price: 299.99 USD & FREE shipping"
  } ],
  "contact" : {
    "address" : "Seocho District, Seoul, South Korea",
    "phone" : "+82-2-2053-3000"
  }
}
==========Find a company by name:==========
{
  "id" : 2,
  "name" : "Samsung",
  "products" : [ {
    "code" : "S-012",
    "name" : "GalaxyJ7",
    "details" : "Price: 219.00 USD & FREE shipping"
  }, {
    "code" : "S-456",
    "name" : "GalaxyTabA",
    "details" : "Price: 299.99 USD & FREE shipping"
  } ],
  "contact" : {
    "address" : "Seocho District, Seoul, South Korea",
    "phone" : "+82-2-2053-3000"
  }
}
==========Find a company by address:==========
{
  "id" : 1,
  "name" : "Apple",
  "products" : [ {
    "code" : "A-123",
    "name" : "Iphone 7",
    "details" : "Price: 649.00 USD & FREE shipping"
  }, {
    "code" : "A-456",
    "name" : "IPadPro",
    "details" : "Price: 417.67 USD & FREE shipping"
  } ],
  "contact" : {
    "address" : "Cupertino, CA 95014",
    "phone" : "1-408-996-1010"
  }
}

Run MongoDB shell by commandline: .\MongoDB\Server\3.4\bin>mongo.exe:

-> Logs:


C:\Program Files\MongoDB\Server\3.4\bin>mongo.exe
MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
Server has startup warnings:
2017-08-18T16:52:34.224+0700 I CONTROL  [initandlisten]
2017-08-18T16:52:34.224+0700 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-08-18T16:52:34.225+0700 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-08-18T16:52:34.225+0700 I CONTROL  [initandlisten]
>

Results with MongoDB shell:

mongodb embedded document - mongodb shell results

show dbs is used to show all MongoDB databases. -> Having one database jsa_mongodb which is created by the SpringBoot MongoRepository application.
use jsa_mongodb is used to select the jsa_mongodb database to work.
show collections is used to show all collections in current database. -> We just have one collection: {company}
db.company.find() is used to query all documents of the collection company. -> We have 2 Company documents {Apple, Samsung}.

IV. Sourcecode

SpringMongoDbEmbeddedDocument

47 thoughts on “MongoDB – Model One-to-One, One-to-Many Relationships Embedded Documents | SpringBoot”

  1. your demo example for one to many relation in mongodb works fine.but in company to address mapping only company collection data is inserted corresponding address collection is empty.

    1. More infomation for right understanding about MongoDB Emdedded model:

      – Emdedded model is the way we embed related data in a single structure or document.

      => So we just have one collection that stores document.
      In the case, We have only company collection. And address collection does not exist.

      Regards,

  2. Hey dude, really nice your demo!

    I just have a silly question,
    Introducing:

    I have two entities: Plant and Plantation. Plant is a document that contains all plants I have (Tomato, Potato, etc), and plantation is another document that contains a Plant and details about plantation (When I sown it).
    I know my thinking is still in ER DB but I cannot understand how I could reuse those plants inside my plantation without create a new/duplicated plant for every single plantation.

    I saw people using a plantId inside plantation and just keep the relationship like a string to another document. But in code perspective it is not nice, because when I am gonna work with my plantation object I will not have my plant as well, only plant ID.

    How could I do that?

    Thank you!

  3. Great example, Just a couple code correction.

    When writing the CompanyRepository.java the types should be specified otherwise the code launches an error:
    org.springframework.data.mapping.MappingException: Couldn’t find PersistentEntity for type class java.lang.Object!

    To avoid this the following addition should be made:
    Instead of: public interface CompanyRepository extends MongoRepository {
    use: public interface CompanyRepository extends MongoRepository {

    When implementing the command line Client (SpringDataMongoDbApplication.java) when saving the documents into the MongoDB there is a mistake generating an error.

    Instead of: companyRepo.save(Arrays.asList( ···
    It should be: companyRepo.saveAll(Arrays.asList(···

  4. I’m really enjoying the design and layout of your website.
    It’s a very easy on the eyes which makes it much more enjoyable for me to come here and visit more often. Did you hire out a designer to create your theme?
    Excellent work!

  5. Greetings! I’ve been following your website for a while now
    and finally got the bravery to go ahead and give you a
    shout out from Dallas Tx! Just wanted to say keep up the
    great work!

  6. Thanks for some other informative site. Where else may just
    I get that kind of info written in such a perfect manner?
    I have a undertaking that I’m just now operating on, and
    I have been at the look out for such info.

  7. I think this is one of the most significant information for
    me. And i am glad reading your article. But want to remark on some general things, The
    website style is ideal, the articles is really excellent : D.
    Good job, cheers

  8. I have been surfing online more than 2 hours today,
    yet I never found any interesting article like yours.
    It is pretty worth enough for me. In my opinion,
    if all site owners and bloggers made good content as you did, the internet will be a lot more useful
    than ever before.

  9. Fascinating blog! Is your theme custom made or did you
    download it from somewhere? A theme like yours with a few simple
    adjustements would really make my blog stand out.
    Please let me know where you got your theme. Many thanks

  10. Hi there, I discovered your website by way of Google at the same time as searching for a related topic, your site got
    here up, it seems good. I’ve bookmarked it in my google bookmarks.

    Hi there, simply was aware of your weblog via Google, and found that it is really informative.
    I’m gonna watch out for brussels. I’ll appreciate if you continue this in future.

    A lot of folks shall be benefited out of your writing.
    Cheers!

  11. Hi there! I could have sworn I’ve been to this web site before
    but after going through some of the articles I realized it’s new to me.
    Nonetheless, I’m definitely delighted I stumbled upon it and I’ll be
    bookmarking it and checking back frequently!

  12. You actually make it seem so easy with your presentation but I find this matter to be really something that I think I would never understand.

    It seems too complex and very broad for me. I’m looking forward for
    your next post, I’ll try to get the hang of it!

  13. Write more, thats all I have to say. Literally, it seems as though you relied on the video to make your point.
    You obviously know what youre talking about, why throw
    away your intelligence on just posting videos to your weblog when you
    could be giving us something informative to read?

  14. When I initially left a comment I appear to have clicked on the -Notify me
    when new comments are added- checkbox and now each time a
    comment is added I recieve 4 emails with the same comment. There has to be a means you
    can remove me from that service? Kudos!

  15. Have you ever considered about adding a little bit more than just your articles?
    I mean, what you say is important and all. However just imagine if you added some great
    photos or video clips to give your posts more, “pop”! Your content is excellent but with pics and videos, this site could definitely be one of the most
    beneficial in its field. Great blog!

  16. When I initially commented I clicked the “Notify me when new comments are added”
    checkbox and now each time a comment is added I get several
    e-mails with the same comment. Is there any way you can remove people from that service?
    Many thanks!

  17. Aw, this was a really nice post. Finding the time and actual effort to generate
    a superb article… but what can I say… I procrastinate a whole lot and never
    seem to get nearly anything done.

  18. I know this if off topic but I’m looking into starting my own weblog
    and was curious what all is required to get set up?
    I’m assuming having a blog like yours would cost a pretty penny?
    I’m not very web smart so I’m not 100% certain. Any recommendations or advice would be greatly appreciated.

    Many thanks

  19. Woah! I’m really loving the template/theme of this blog.
    It’s simple, yet effective. A lot of times it’s difficult to get that “perfect balance” between usability and visual
    appearance. I must say you’ve done a great job with
    this. Also, the blog loads extremely quick for me on Internet explorer.
    Outstanding Blog!

  20. Excellent goods from you, man. I’ve understand your stuff previous to and you’re just extremely fantastic. I really like what you’ve acquired here, really like what you’re saying and the way in which you say it. You make it enjoyable and you still take care of to keep it wise. I cant wait to read far more from you. This is actually a wonderful site.

Leave a Reply

Your email address will not be published. Required fields are marked *