Spring Data Mongodb - repository for collection with different types

10,698

Solution 1

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.

Solution 2

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

Share:
10,698
SimY4
Author by

SimY4

Gamer, Geek, Software developer

Updated on June 20, 2022

Comments

  • SimY4
    SimY4 almost 2 years

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