I've got a MongoDB collection with the following document structure:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Document
public class CustomerRouteManagementReportDocument implements TransactionDocument {
@Id
private String id;
@Indexed(unique = true)
private String customerId;
// ... other properties
private List<RouteHistoryEvent> routeHistoryEvents;
// ... other properties
}
Essentially, the following method should perform a bulk upsert: if a matching entry is found, it should append the first item from the routeHistoryEvents
item into the existing document' routeHistoryEvents
array. Otherwise, a whole new CustomerRouteManagementReportDocument
should be inserted into the collection.
@Service
@Slf4j
public class CustomerRouteManagementReportRepositoryAdapter extends AbstractRepositoryAdapter<CustomerRouteManagementReport, CustomerRouteManagementReportDocument, CustomerRouteManagementReportDataRepository> implements CustomerRouteManagementReportRepository {
private final MongoTemplate mongoTemplate;
@Autowired
public CustomerRouteManagementReportRepositoryAdapter(ModelMapper mapper, CustomerRouteManagementReportDataRepository repository, MongoTemplate mongoTemplate) {
super(mapper, repository, CustomerRouteManagementReport.class, CustomerRouteManagementReportDocument.class);
this.mongoTemplate = mongoTemplate;
}
//... other methods
@Override
public Integer upsertTall(List<CustomerRouteManagementReportDocument> customerRouteManagementReports) {
BulkOperations bulkOps = mongoTemplate.bulkOps(BulkOperations.BulkMode.ORDERED, CustomerRouteManagementReportDocument.class);
try {
List<Pair<Query, Update>> updates = new ArrayList<>();
customerRouteManagementReports.stream().forEach(customerRouteManagementReport -> {
Query query = Query.query(Criteria.where("customerId").is(customerRouteManagementReport.getCustomerId()));
Update update = new Update();
update.addToSet("routeHistoryEvents").value(customerRouteManagementReport.getRouteHistoryEvents().get(0));
updates.add(Pair.of(query, update));
});
bulkOps.upsert(updates);
BulkWriteResult result = bulkOps.execute();
log.info("== BULK RESULT: {}, INSERTED: {}", result, result.getInsertedCount());
return result.getInsertedCount();
}
catch (Exception e) {
log.error("ERROR {}: IN UPSERTION {}", e.getClass().toGenericString(), e.getMessage());
return 0;
}
}
}
The problem is that no updates nor insertions are being made and no exception is raised either. I've tried with both an empty collection and a collection loaded with documents that will meet the query
condition and should be updated, but my log simply reads:
== BULK RESULT: AcknowledgedBulkWriteResult{insertedCount=0, matchedCount=4, removedCount=0, modifiedCount=4, upserts=[]}, INSERTED: 0
However, in debugging, the method is called and it shows the appropriate number of Pair
s for the number of objects that the usecase receives to process:
No MongoTemplate
logs are issued (not even for the find
operation that, I presume, it must perform in order to update my collection) which leads me to think that maybe my class doesn't have a proper MongoTemplate
configured. However, there are no connection errors thrown either. This is our config class for MongoDB:
@Configuration
@ConditionalOnProperty(name = "spring.data.mongodb.uri-report")
@EnableReactiveMongoRepositories(basePackages = "package name",
reactiveMongoTemplateRef = ReportMongoConfig.REPORT_REACTIVE_MONGO_TEMPLATE)
public class ReportMongoConfig {
protected static final String REPORT_REACTIVE_MONGO_TEMPLATE = "reportReactiveMongoTemplate";
@Value("${spring.data.mongodb.uri-report}")
private String connectionStringReport;
@Bean
public ConnectionString getConnectionDataBaseReport() {
return new ConnectionString(connectionStringReport);
}
@Bean
public ReactiveMongoTemplate reportReactiveMongoTemplate(MappingMongoConverter mappingMongoConverter) {
return new ReactiveMongoTemplate(reactiveReportMongoDatabaseFactory(getConnectionDataBaseReport()), mappingMongoConverter);
}
@Bean
public MongoTemplate mongoTemplate(MappingMongoConverter mappingMongoConverter) {
return new MongoTemplate(reportMongoDBFactory(getConnectionDataBaseReport()), mappingMongoConverter);
}
@Bean
public ReactiveMongoDatabaseFactory reactiveReportMongoDatabaseFactory(ConnectionString getConnectionDataBaseExperience) {
return new SimpleReactiveMongoDatabaseFactory(getConnectionDataBaseExperience);
}
@Bean
public MongoDbFactory reportMongoDBFactory(ConnectionString connectionString) {
return new SimpleMongoClientDbFactory(connectionString);
}
}
I'm wondering if there's an injection issue when providing the appropriate MongoTemplate
bean to the repository class or if there's an issue with the queries built inside the upsertAll
method.
It turned out that somewhere else in a the application there's another MongoTemplate
bean connected to a different collection. Organizing the beans using @Primary
and @Qualifier
solved the issue.