Reputation: 2469
I'm using Spring Data for Mongo on an existing database. The previous application used plain strings for ids instead of ObjectId.
My problem is that Spring Data insists on converting the strings to ObjectId, which makes all queries by id to fail.
For example, when I do repository.findOne('')
, the query executed is { "_id" : { "$oid" : "50cf9f34458cf91108ceb2b4"}}
when it should be { "_id" : "50cf9f34458cf91108ceb2b4" }
Is there a way to avoid Spring Data to convert string ids to ObjectId?
Thanks!
Diego
Upvotes: 9
Views: 6660
Reputation: 1
Somehow if you are not able to use annotations on the entity class then you can extend CachingMongoPersistentProperty to override isIdProperty() method. This will prevent converting "id" properties to "_id":
public class NotEditableEntityMongoPersistentProperty extends CachingMongoPersistentProperty {
public NotEditableEntityMongoPersistentProperty(final Property property, final MongoPersistentEntity<?> owner,
final SimpleTypeHolder simpleTypeHolder, final FieldNamingStrategy fieldNamingStrategy) {
super(property, owner, simpleTypeHolder, fieldNamingStrategy);
}
@Override
public boolean isIdProperty() {
return false;
}
}
Then use this on MongoMappingContext:
public class NotEditableEntityMongoMappingContext extends MongoMappingContext {
@Override
public MongoPersistentProperty createPersistentProperty(final Property property, final BasicMongoPersistentEntity<?> owner,
final SimpleTypeHolder simpleTypeHolder) {
return new NotEditableEntityMongoPersistentProperty(property, owner, simpleTypeHolder, PropertyNameFieldNamingStrategy.INSTANCE);
}
}
Then
@Bean
public MongoTemplate mongoTemplate(@Autowired final MongoDatabaseFactory mongoDbFactory) {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
MongoMappingContext mappingContext = new NotEditableEntityMongoMappingContext();
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext);
return new MongoTemplate(mongoDbFactory, converter);
}
Upvotes: 0
Reputation: 602
Field annotation with FieldType=IMPLICIT worked for me
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
public class FilesInUploading {
@Id
@Field(targetType = FieldType.IMPLICIT)
private String id;
...
}
I also tried with FieldType=STRING
. But $nin, $in
queries not worked for me at that time.
Upvotes: 0
Reputation: 543
You can use the Field annotation.
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Dog{
@Id
@Field(targetType = FieldType.STRING)
String myId;
...
}
Upvotes: 3
Reputation: 177
I've found a simpler approach to the same one serhii
took where you only override the method convertId
in MobileMappingMongoConverter
class, you'll find it in this post.
Upvotes: 0
Reputation: 71
now enough just override convertId method in MappingMongoConverter.
default here https://github.com/spring-projects/spring-data-mongodb/blob/master/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverter.java#L128. As we can see, conversionService will no so helpful.
that's part of my config (I don't need ObjectId from string at all in my collections):
@Configuration
public class MongoCommonConfig extends AbstractMongoClientConfiguration {
...
@Bean
@Primary
public MongoTemplate mongoTemplate(MongoDbFactory dbFactory,
MappingMongoConverter mappingMongoConverter) {
return new MongoTemplate(dbFactory, mappingMongoConverter);
}
@Bean
@Primary
@Override
public @NotNull MappingMongoConverter mappingMongoConverter() throws Exception {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext()) {
@Override
public Object convertId(Object id, @NotNull Class<?> targetType) {
return id;
}
};
converter.setCustomConversions(customConversions());
converter.setCodecRegistryProvider(mongoDbFactory());
return converter;
}
...
}
Upvotes: 1
Reputation: 21
I've faced same problem and my solution was like below:
@Bean
public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, MongoMappingContext context, CustomConversions conversions) {
MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(factory), context) {
@Override
public void afterPropertiesSet() {
conversions.registerConvertersIn(conversionService);
}
};
converter.setCustomConversions(conversions);
return converter;
}
The idea is to prevent default converters registration.
Upvotes: 1
Reputation: 2469
I finally found a solution for this. Probably not the best option, but works.
What I did was remove the converter from String
to ObjectId
that MongoTemplate
uses through QueryMapper
. This way, I created the following Mongo converter:
public class CustomMongoConverter extends MappingMongoConverter {
public CustomMongoConverter(MongoDbFactory mongoDbFactory, MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
super(mongoDbFactory, mappingContext);
conversionService.addConverter(new Converter<String, ObjectId>() {
@Override
public ObjectId convert(String source) {
throw new RuntimeException();
}
});
}
}
And then, I passed that implementation of the converter to MongoTemplate
:
<bean id="mongoConverter" class="com.abcompany.model.repositories.utils.CustomMongoConverter">
<constructor-arg ref="mongoDbFactory"/>
<constructor-arg>
<bean class="org.springframework.data.mongodb.core.mapping.MongoMappingContext"/>
</constructor-arg>
</bean>
<bean class="org.springframework.data.mongodb.core.MongoTemplate" id="mongoTemplate">
<constructor-arg ref="mongoDbFactory"/>
<constructor-arg ref="mongoConverter"/>
</bean>
This way, when trying to convert from String to ObjectId, it throws an exception and it doesn't do it. Please note that you probably can just remove the converter from conversionService
.
Upvotes: 1