3

Use case: I want to have two collections which have same fields. One collection will have recent data (say 15 days)and other have old data(say last 6 months). I want to achieve this with a single POJO as it will be easier to do query based on date and then convert it to VOs.

Bottom line: I want to create 2 collections from 1 POJO.

Please suggest.

nitesh goel
  • 6,338
  • 2
  • 29
  • 38

2 Answers2

0

I had the same problem. I don't think it is easily doable because the collection name is set in the @Document annotation which sits on your POJO. It is possible to change it dynamically by using SpEL expressions (see e.g. How To Configure MongoDb Collection Name For a Class in Spring Data) and there are some examples where this can be used for multi-tenancy or multiple principles but I don't see how to use this at compile time to create two different beans from the same class. To my knowledge that is not possible.

I can offer possible solutions but both are ugly af.

  1. This is the workaround I actually used. Create child classes for the document and put the acutal logic into the parent

Parent class

@Getter
@FieldDefaults(makeFinal=true, level= AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@EqualsAndHashCode
public class CommonParent {

    @Id
    @Delegate
    HourlySiteWaiterRevenue.Key key;
    long count;
    @Field(targetType = FieldType.DECIMAL128)
    BigDecimal sum;

    @CompoundIndex
    @Value
    public static class Key implements Serializable {
        @NonNull UUID entityId;
        @NonNull Instant timestamp;
    }
}

Actual model for repository

@Document
public class UseThisForRepository extends CommonParent{
    public UseThisForRepository(@NonNull @JsonProperty("key") CommonParent.Key key,
            @NonNull @JsonProperty("count") long count,
            @NonNull @JsonProperty("sum") BigDecimal sum,) {
        super(key, count, sum);
    }
}

The model for the repository exclusively consists of boilerplate code that must be copypasted multiple times just so you can have multiple @Document annotations. This will by default use the child class name as collection name but is configurable everywhere.

  1. mongoTemplate in principle has overloads with the collection name. It is possible to configure the collection name in the mongoTemplate (see e.g. https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo-template). It should be possible to have different collection names and use those. However, I can't think of a way how to use this name in the classes Spring autogenerates from the @Repository interface. You could overwrite every single repository method in a RepositoryCustom implementation but then you could just not use @Repository at all.
maow
  • 2,712
  • 1
  • 11
  • 25
-1
  1. Considering you have similar POJO

    @Document(collection = "domain")
    public class Domain {
    
        @Id
        private long id;
    
        @Indexed(unique = true)
        private String name;
    
        private Date createdDate;
    
        //getters and setters 
    }
    
  2. You can write QueryMethods in Repo to extract conditional data from a POJO

    public interface DomainRepository extends MongoRepository<Domain, Long> {
    
        Domain findFirstByName(String domain);
    
        List<Domain> findByCreatedDateBetween(Date thresholdDate1, Date thresholdDate2);
    
    }
    
  3. Call QueryMethods in your controller/methods to get the desired collections

    @Autowired
    DomainRepository domainRepo;
    
    List<Domain> 15daysOld = domainRepo.findByCreatedDateBetween(15daysOldDate, currentDate);
    List<Domain> 6monthsOld = domainRepo.findByCreatedDateBetween(6monthsOldDate, currentDate);
    
Neuron
  • 5,141
  • 5
  • 38
  • 59
UsamaAmjad
  • 4,175
  • 3
  • 28
  • 35