You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data MongoDB中基于单个POJO创建双集合的实现方案咨询

Great question! This is a common scenario for balancing query performance and data retention in MongoDB, and using a single POJO is absolutely feasible. Let’s break down the best approaches to make this work smoothly:

Approach 1: Direct MongoTemplate Operations (Simplest & Most Flexible)

Skip tying your POJO to any fixed collection—use MongoTemplate to explicitly target either collection for every operation. This keeps your POJO clean and gives you full control.

Step 1: Define Your Reusable POJO

No @Document annotation needed (or you can add it with a default collection, but we’ll override it anyway):

import org.springframework.data.annotation.Id;
import java.time.LocalDateTime;

public class DataRecord {
    @Id
    private String id;
    private String userId;
    private String payload;
    private LocalDateTime createdAt;

    // Getters, setters, and basic constructors
}

Step 2: Service Layer with Explicit Collection Targeting

Inject MongoTemplate and write methods to interact with either collection directly:

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class DataRecordService {
    private final MongoTemplate mongoTemplate;
    private static final String RECENT_COLLECTION = "recent_data";
    private static final String HISTORICAL_COLLECTION = "historical_data";

    public DataRecordService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    // Fetch recent data (last 15 days)
    public List<DataRecord> getRecentData() {
        LocalDateTime fifteenDaysAgo = LocalDateTime.now().minusDays(15);
        Query query = Query.query(Criteria.where("createdAt").gte(fifteenDaysAgo));
        return mongoTemplate.find(query, DataRecord.class, RECENT_COLLECTION);
    }

    // Fetch historical data (up to 6 months old)
    public List<DataRecord> getHistoricalData(LocalDateTime startDate, LocalDateTime endDate) {
        Query query = Query.query(Criteria.where("createdAt").between(startDate, endDate));
        return mongoTemplate.find(query, DataRecord.class, HISTORICAL_COLLECTION);
    }

    // Save new data directly to the recent collection
    public DataRecord saveNewRecord(DataRecord record) {
        record.setCreatedAt(LocalDateTime.now());
        return mongoTemplate.save(record, RECENT_COLLECTION);
    }
}

Approach 2: Dynamic Collection Names with Spring Data Repositories

If you prefer the Spring Data repository pattern, use a dynamic collection resolver to map your POJO to either collection at runtime.

Step 1: POJO with Dynamic Collection Annotation

Use a SpEL expression to resolve the collection name via a custom bean:

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

@Document(collection = "#{@collectionResolver.getCollectionName(#root)}")
public class DataRecord {
    @Id
    private String id;
    private String userId;
    private String payload;
    private LocalDateTime createdAt;

    // Getters, setters, constructors
}

Step 2: Collection Resolver Bean

This bean decides which collection to use based on the record’s timestamp or a passed flag:

import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

@Component("collectionResolver")
public class CollectionResolver {
    // Resolve for existing records
    public String getCollectionName(DataRecord record) {
        return record.getCreatedAt().isAfter(LocalDateTime.now().minusDays(15)) 
            ? "recent_data" 
            : "historical_data";
    }

    // Resolve for query scenarios (no record available)
    public String getCollectionName(boolean isRecent) {
        return isRecent ? "recent_data" : "historical_data";
    }
}

Step 3: Custom Repository Methods

Use the resolver in your repository to query the correct collection:

import org.springframework.data.mongodb.repository.MongoRepository;
import java.time.LocalDateTime;
import java.util.List;

public interface DataRecordRepository extends MongoRepository<DataRecord, String> {
    default List<DataRecord> findRecentRecords(LocalDateTime startDate) {
        String collectionName = ((CollectionResolver) ApplicationContextProvider.getBean("collectionResolver"))
                .getCollectionName(true);
        return mongoTemplate.find(
            Query.query(Criteria.where("createdAt").gte(startDate)),
            DataRecord.class,
            collectionName
        );
    }
}

Handling Data Migration

You’ll need to periodically move data from recent_data to historical_data once it’s older than 15 days. Add a scheduled task to your service:

// Add to DataRecordService
import org.springframework.scheduling.annotation.Scheduled;

@Scheduled(cron = "0 0 2 * * ?") // Runs daily at 2 AM
public void migrateOldData() {
    LocalDateTime cutoff = LocalDateTime.now().minusDays(15);
    Query query = Query.query(Criteria.where("createdAt").lt(cutoff));

    // Fetch and migrate records
    List<DataRecord> oldRecords = mongoTemplate.find(query, DataRecord.class, RECENT_COLLECTION);
    if (!oldRecords.isEmpty()) {
        mongoTemplate.insertAll(oldRecords, HISTORICAL_COLLECTION);
        // Delete from recent collection after successful migration
        mongoTemplate.remove(query, DataRecord.class, RECENT_COLLECTION);
    }
}

Converting to VO Seamlessly

Since both collections return the same DataRecord POJO, converting to your VO is trivial. Use a mapping library like MapStruct for clean, type-safe conversions:

MapStruct Mapper Example

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;

@Mapper(componentModel = "spring")
public interface DataRecordMapper {
    DataRecordMapper INSTANCE = Mappers.getMapper(DataRecordMapper.class);

    DataVO toVO(DataRecord record);
    List<DataVO> toVOList(List<DataRecord> records);
}

Usage in Service

// Update getRecentData() in DataRecordService
public List<DataVO> getRecentDataAsVO() {
    List<DataRecord> records = getRecentData();
    return DataRecordMapper.INSTANCE.toVOList(records);
}

内容的提问来源于stack exchange,提问作者nitesh goel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:45:59