Closed
Description
Description
When using Spring Data MongoDB with entities annotated with @MongoId String id
, there is an inconsistency in how the _id
field is stored in MongoDB depending on whether save
or saveAll
is used. Specifically, save
stores the _id
as a String
, while saveAll
stores it as an ObjectId
, even though the ID is not explicitly set in either case.
That even leads to duplication in the DB, since when used saveAll
and the update
it will convert it to string but creates a duplicated object
Steps to Reproduce
- Set up a Spring Boot project with the following dependencies:
- Spring Boot Starter Data MongoDB
- Run the application and observe the output.
- Check the DB
package com.example.mongo_bug;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
@SpringBootApplication
public class MongoBugApplication {
public static void main(String[] args) {
SpringApplication.run(MongoBugApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(MyRepository repository) {
return args -> {
// Create entities without setting ID
MyEntity entity1 = new MyEntity();
entity1.setName("Entity1");
MyEntity entity2 = new MyEntity();
entity2.setName("Entity2");
// Save using save
repository.save(entity1);
// Save using saveAll
repository.saveAll(List.of(entity2));
// Update the name of entity2 will lead to duplicate
entity2.setName("UpdatedEntity2");
repository.save(entity2);
// Find all entities
List<MyEntity> allEntities = repository.findAll();
allEntities.forEach(entity -> System.out.println("Entity ID: " + entity.getId() + ", Name: " + entity.getName()));
};
}
}
// Repository interface
interface MyRepository extends MongoRepository<MyEntity, String> {
}
// Entity class
@Document
class MyEntity {
@MongoId
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Expected Behavior
- Both
save
andsaveAll
store_id
as a String in MongoDB whenid
isnull
and the field isString
.
Actual Behavior
save
stores_id
as aString
.saveAll
stores _id as anObjectId
.- Updating an entity saved with
saveAll
creates a duplicate due to the type mismatch.
{
_id: '67f82b6888d11c0743a9097f',
name: 'Entity1',
_class: 'com.example.mongo_bug.MyEntity'
}
{
_id: ObjectId("67f82b6888d11c0743a90980"),
name: 'Entity2',
_class: 'com.example.mongo_bug.MyEntity'
}
{
_id: '67f82b6888d11c0743a90980',
name: 'UpdatedEntity2',
_class: 'com.example.mongo_bug.MyEntity'
}
Environment
- Spring Boot Version: 3.4.4
- Spring Data MongoDB Version: 4.4.4
- MongoDB Version: 8.0.6
- Java Version: temurin-22.0.2
- Operating System: Ubuntu 24.04.2 LTS