skip to Main Content

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 Pairs for the number of objects that the usecase receives to process:
enter image description here

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.

2

Answers


  1. Chosen as BEST ANSWER

    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.


  2. The problem is that no updates nor insertions are being made and no
    exception is raised either.

    Log

    BULK RESULT: AcknowledgedBulkWriteResult{insertedCount=0,
    matchedCount=4, removedCount=0, modifiedCount=4, upserts=[]},
    INSERTED: 0

    The above statement is wrong. As is clearly shown from the logs there are 4 updates -> matchedCount=4 modifiedCount=4.

    So you need to check why somehow there is a match that triggers an update instead of an insert during this upsert.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search