Skip to content

Inconsistent _id Storage Type Between save and saveAll for @MongoId String id #4944

Closed
@initdch

Description

@initdch

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

  1. Set up a Spring Boot project with the following dependencies:
    • Spring Boot Starter Data MongoDB
  2. Run the application and observe the output.
  3. 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 and saveAll store _id as a String in MongoDB when id is null and the field is String.

Actual Behavior

  • save stores _id as a String.
  • saveAll stores _id as an ObjectId.
  • 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'
}

Image

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

Test Project To Reproduce

mongo-bug.zip

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions