1

I am new to MongoDB and NoSQL databases and I am trying to learn different kind of thinking that everybody mentions when it comes to NoSQL.

I have a typical situation with many-to-one relationship. Please don't tell me that MongoDB is not a relational database, because I know that already. Key point is - reality works certain way and I need to make my application to reflect it. Real world is full of relationships and if your answer is "choose a different DB for your case" then I think that MongoDB team could close their business, because their product would be completely useless in such a case.

So let's assume typical Employee / Department relation. Employee is linked to a single Department. Department can have zero or multiple Employees.

Let's assume super simple models:

public class Department {

    private String name;

   // something like...
   private List<Employee> employees;

}

public class Employee {

    private String name;

   // something like...
   private Department department;

}

Now in my REST API I need few quite basic functionalities:

  • get list of all departments
  • get list of all employees, but it must contain name of department for each employee
  • get list of employees for a selected department

So how would you solve this with MongoDB? I am also using Spring Boot with Spring Data, but I think it doesn't matter very much.

I have come across different approaches, but all seem very bad to me. Embedding department inside employee will make it impossible to get list of all departments or employees of a single department. Embedding employees in department will make it impossible to get list of all employees. Using @DbRef will simulate the relation, but then how do I get list of employees including the department names without calling REST API for each employee?

I have read quite a lot of tutorials, manuals and StackOverflow discussions recently, but I haven't found acceptable answer. Is it really possible that MongoDB can't solve such a super-simple problem? It is not even a problem, it is rather a standard - common situation in the world around us.

thank you

lot
  • 1,434
  • 18
  • 23
  • "Is it really possible that MongoDB can't solve such a super simple problem?" - MongoDB is about documents, not entities with relationships. The easiest way would be to have one collection with the departments for your "get list of all departments" use case and one collection with all employees with their department ID and/or name for your second and third use case. If you care more about consistency than runtime, an employee may contain only the ID of the department but then you have to access the "department" collection for every employee to load his departments name. – Smutje Apr 02 '19 at 13:14
  • I don't think there even exists such a situation in real world, where you'd have entities without any relationships between them. If MongoDB is really built upon such assumption then OMG :-) – lot Apr 02 '19 at 13:33
  • Could you please clarify "access the "department" collection for every employee to load his departments name"? I mean - how do I implement this in Java Spring? – lot Apr 02 '19 at 13:38
  • 1
    Relationships can be replaced with redundancy, that is MongoDB's stance. Regarding your question: I queried MongoDB manually so after loading all employees you have to map the MongoDB documents into your own data model where you to create a `Employee` object you have to load the appropriate `Department` (filtered by ID) out of the departments collection. I have no clue what Spring Data is able to do with MongoDB though. – Smutje Apr 02 '19 at 14:07
  • thank you, in the end I managed to implement that. Not so happy about this method, but at least it works. – lot Apr 03 '19 at 22:02

1 Answers1

2

Maybe you can use a simple departmentId (with the value of the Mongo ID for the department) in your Employee document?

This way you avoid the embedded document and your use cases can work :

  1. All departments case is simply a find-all in the departments collection.
  2. All employees is a find-all in the employees collection and then in your server you need to call the department collection for all the distinct department ids that exist in the employees.
  3. All employees for a selected department case is a find-by-departmentId in the employees collection.

Would this work for you in an acceptable manner?

Nick Tsitlakidis
  • 2,269
  • 3
  • 22
  • 26
  • if I understand correctly then you suggest to create a reference (in Spring Data it is done with @DbRef). How exactly you handle second use-case then? Can you even attach Java code? – lot Apr 02 '19 at 13:29
  • I'm not suggesting a DbRef. I'm suggesting a simple String property which contains Mongo's id. Then it's up to you in another application layer to fill your response objects with full Department documents after you complete all queries. – Nick Tsitlakidis Apr 02 '19 at 14:04
  • ok, thank you. I will give it a try. Would you have a suggestion how exactly implement this in Java Spring? – lot Apr 02 '19 at 14:07
  • Given that you use Spring data, you probably will have a DepartmentRepository and an EmployeeRepository. You will have to coordinate calls to both of them. First you can use findAll() in the EmployeeRepository and then based on the department ids you get from the Employee objects, you can use the findAllById() method of the DepartmentRepository. based on both results you can then create your API response. – Nick Tsitlakidis Apr 02 '19 at 14:11
  • Thank you for your advice. This is what I've done in the end and it works. I can't help myself thinking that it is rather a workaround - reimplementing relational database using MongoDB. Making views and ensuring data consistency gets harder this way and choosing MongoDB was indeed a mistake. – lot Apr 03 '19 at 22:05
  • 1
    @lot: you're totally right! MongoDBs strength is handling, searching, filtering self-contained documents and definitely not simulating relational databases. E.g. in a past project we used MongoDB as a kind of persistent cache filterable in a efficient way compared to a self-made in-memory cache. – Smutje Apr 04 '19 at 06:57