Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data Mongodb - repository for collection with different types

I have a mongo collection that may contain three types of entities that I map to java types:

  • Node
  • LeafType1
  • LeafType2

Collection is ment to store tree-like structure using dbRefs of child nodes in parent entry.

I didn't find any information about subject in Spring reference documentation so I'm asking here: Is there a way to use Repository mechanism to work with collection that may contain different types of objects?

Declaring several repositories for different types in one collection seems like not very good idea because I always struggle with situations when queried object is not of expected type and creating one repository for abstract class that all possible types inherrit doesn't seems to work.

To illustrate what I mean:

/**
 * This seems not safe
 */
public interface NodeRepository extends MongoRepository<Node, String> { }
public interface LeafType1Repository extends MongoRepository<LeafType1, String> { }
public interface LeafType2Repository extends MongoRepository<LeafType2, String> { }

/**
 * This doesn't work at all
 */
public interface MyCollectionRepository extends MongoRepository<AbstractMyCollectionNode, String> { }
like image 695
SimY4 Avatar asked Dec 02 '14 09:12

SimY4


People also ask

What is the difference between MongoOperations and MongoTemplate?

MongoTemplate provides a simple way for you to save, update, and delete your domain objects and map those objects to documents stored in MongoDB. You can save, update and delete the object as shown below. MongoOperations is the interface that MongoTemplate implements.

How do I join two MongoDB collections in spring boot?

For performing MongoDB Join two collections, you must use the $lookup operator. It is defined as a stage that executes a left outer join with another collection and aids in filtering data from joined documents. For example, if a user requires all grades from all students, then the below query can be written: Students.

Can we use JPA Repository for MongoDB?

Yes, DataNucleus JPA allows it, as well as to many other databases. You make compromises by using the JPA API for other types of datastores, but it makes it easy to investigate them.

What is MongoTemplate used for?

MongoTemplate — MongoTemplate implements a set of ready-to-use APIs. A good choice for operations like update, aggregations, and others, MongoTemplate offers finer control over custom queries. MongoRepository — MongoRepository is used for basic queries that involve all or many fields of the document.


2 Answers

If Node\LeafType1\LeafType2 are sub-classes of AbstractMyCollectionNode, then things will be easy. Just declare the repository like you write:

public interface MyCollectionRepository extends MongoRepository<AbstractMyCollectionNode, String> { }

We have done this in a project, and it works good. Spring Data will add an property named '_class' to the documents in mongodb collection, so that it can finger out which class to instantiate.

Documents that stored in one collection may have some similarity, maybe you can extract a generic class for them.

Here are some code copied from one of our projects:

Entity:

public abstract class Document {
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
    ....

public class WebClipDocument extends Document {
    private String digest;
    ...

Repository:

public interface DocumentDao extends MongoRepository<Document, String>{
...

And, if your documents in mongodb collection does not have the "_class" property. You can use Converter:

When storing and querying your objects it is convenient to have a MongoConverter instance handle the mapping of all Java types to DBObjects. However, sometimes you may want the `MongoConverter’s do most of the work but allow you to selectively handle the conversion for a particular type or to optimize performance.

like image 97
Leon Avatar answered Nov 05 '22 14:11

Leon


Spring data uses the Repository-Declarations as entry-point when looking for Entity classes (it does not scan packages for entities directly).

So all you need to do is to declare an "unused" Repository-Interface for your sub-classes, just like you proposed as "unsafe" in your OP:

public interface NodeRepository extends MongoRepository<Node, String> { 
  // all of your repo methods go here
  Node findById(String id);
  Node findFirst100ByNodeType(String nodeType);
  ... etc.
}
public interface LeafType1Repository extends MongoRepository<LeafType1, String> {
  // leave empty
}
public interface LeafType2Repository extends MongoRepository<LeafType2, String> { 
  // leave empty
}

You do not have to use the additional LeafTypeX repositories, you can stick with the NodeRepository for storing and looking up objects of type LeafType1 and LeafType2. But the declaration of the other two repositories is needed, so that LeafType1 and LeafType2 will be found as Entities when initial scanning takes place.

PS: This all assumes, of course, that you have @Document(collection= "nodes") annotations on your LeafType1 and LeafType2 classes

like image 34
cheppsn Avatar answered Nov 05 '22 13:11

cheppsn