Search code examples
javaspring-bootspring-dataspring-mongodb

Repository interface saves only last object instance when in a for loop and bulk insert changes objects before saving


I am iterating over a list of objects and saving one object at a time after each loop. What i found is that only the last object is always saved when using the MongoRepository interface.

for instance

for(int i=0;i<=objectList.size();i++){
    repositoryInterface.save(objectList.get(i));
}

In this case,only the last object is saved when there are about 3 objects in objectList.

Again, if repositoryInterface is used to save all the objectList in one query, say, repositoryInterface.save(objectList), only the last changes to the last object in objectList is persisted for all three objects in objectList. For instance,

public class Book {
    private String bookName;
    private int bookNumber;
    //then getters and setters
}


List<Book> books = new ArrayList<>();
Book book0 = new Book();
book0.setBookName("Book0");
book0.setBookNumber(0);

books.add(book0);

Book book1 = new Book();
book1.setBookName("Book1");
book1.setBookNumber(1);

books.add(book1);

for(int i=0;i< books.size();i++){
    switch(i){
        case 0 :  
            books.get(0).setBookNumber(00);
            break;
        case 1 :
            books.get(1).setBookNumber(11);
            break;
        default:
            System.out.println("nothing per this example");
    }
}

repositoryInterface.save(books);

now checking the mongo database,what is inserted is

{bookName:"Book0",bookNumber:11},{bookName:"Book1",bookNumber:11} 

instead of

{bookName:"Book0",bookNumber:00},{bookName:"Book1",bookNumber:11}

Solution

  • If one fixes some basic issues with the code it works just fine. Here is the code I tried to reproduce the issue, but which runs without a problem (package and import statements excluded):

    The Book class:

    public class Book {
        private String bookName;
        private int bookNumber;
    
        public String getBookName() {
            return bookName;
        }
    
        public void setBookName(String bookName) {
            this.bookName = bookName;
        }
    
        public int getBookNumber() {
            return bookNumber;
        }
    
        public void setBookNumber(int bookNumber) {
            this.bookNumber = bookNumber;
        }
    }
    

    The RepositoryInterface

    public interface RepositoryInterface extends MongoRepository<Book, String>{
    
    }
    

    The Bean containing the actual code to execute. Use either method in doSomething in order to process the books one by one or as a single list.

    @Component
    public class RunCode {
    
        private final RepositoryInterface repositoryInterface;
    
        public RunCode(RepositoryInterface repositoryInterface) {
            this.repositoryInterface = repositoryInterface;
        }
    
        @PostConstruct
        public void doSomething() {
           // updateAsList();
            updateOneByOne();
        }
    
        private void updateOneByOne() {
            List<Book> books = createBookList();
            for(int i=0;i<books.size();i++){
                repositoryInterface.save(books.get(i));
            }
        }
    
        private void updateAsList() {
            List<Book> books = createBookList();
    
            for (int i = 0; i < books.size(); i++) {
                switch (i) {
                    case 0:
                        books.get(0).setBookNumber(00);
                        break;
                    case 1:
                        books.get(1).setBookNumber(11);
                        break;
                    default:
                        System.out.println("nothing per this example");
                }
            }
    
            repositoryInterface.save(books);
        }
    
        private List<Book> createBookList() {
            List<Book> books = new ArrayList<>();
            Book book0 = new Book();
            book0.setBookName("Book0");
            book0.setBookNumber(0);
    
            books.add(book0);
    
            Book book1 = new Book();
            book1.setBookName("Book1");
            book1.setBookNumber(1);
    
            books.add(book1);
            return books;
        }
    }