mongotemplate example data conectar con mongodb spring-data spring-data-mongodb

example - spring mongodb repository



Datos de primavera MongoDb: MappingMongoConverter eliminar_class (7)

Así que aquí está la historia: agregamos el tipo por defecto como algún tipo de sugerencia de qué clase crear una instancia en realidad. Como tiene que canalizar en un tipo para leer el documento en MongoTemplate todos modos, hay dos opciones posibles:

  1. Usted entrega un tipo al que se puede asignar el tipo almacenado real. En ese caso, consideramos el tipo almacenado, utilízalo para la creación de objetos. El ejemplo clásico aquí es hacer consultas polimórficas. Supongamos que tiene un Contact clase abstracta y su Person . A continuación, puede consultar Contact y, básicamente, tenemos que determinar un tipo para crear instancias.
  2. Si, por otro lado, pasas de un tipo completamente diferente, simplemente ingresaremos en ese tipo dado, no en el almacenado en el documento en realidad. Eso cubriría su pregunta de qué pasa si mueve el tipo.

Es posible que esté interesado en ver este ticket que cubre algún tipo de estrategia de mapeo de tipo conectable para convertir la información de tipo en un tipo real. Esto puede servir simplemente para ahorrar espacio, ya que es posible que desee reducir un nombre de clase calificado largo a un hash de algunas letras. También permitiría escenarios de migración más complejos en los que podría encontrar claves de tipo completamente arbitrarias producidas por otro cliente de almacenamiento de datos y vincularlas a tipos de Java.

El MappingMongoConverter predeterminado agrega una clave de tipo personalizada ("_class") a cada objeto en la base de datos. Entonces, si creo una Persona:

package my.dto; public class Person { String name; public Person(String name) { this.name = name; } }

y guárdalo en el db:

MongoOperations ops = new MongoTemplate(new Mongo(), "users"); ops.insert(new Person("Joe"));

el objeto resultante en el mongo será:

{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }

Preguntas:

  1. ¿Cuáles son las implicaciones de mover la clase Persona a un espacio de nombres diferente?

  2. ¿Es posible no contaminar el objeto con la tecla "_clase"; sin escribir un convertidor único solo para la clase Persona?


Aquí está mi anotación, y funciona.

@Configuration public class AppMongoConfig { public @Bean MongoDbFactory mongoDbFactory() throws Exception { return new SimpleMongoDbFactory(new Mongo(), "databasename"); } public @Bean MongoTemplate mongoTemplate() throws Exception { //remove _class MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()); converter.setTypeMapper(new DefaultMongoTypeMapper(null)); MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter); return mongoTemplate; } }


<mongo:mongo host="hostname" port="27017"> <mongo:options ...options... </mongo:mongo> <mongo:db-factory dbname="databasename" username="user" password="pass" mongo-ref="mongo"/> <bean id="mongoTypeMapper" class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper"> <constructor-arg name="typeKey"><null/></constructor-arg> </bean> <bean id="mongoMappingContext" class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" /> <bean id="mongoConverter" class="org.springframework.data.mongodb.core.convert.MappingMongoConverter"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /> <constructor-arg name="mappingContext" ref="mongoMappingContext" /> <property name="typeMapper" ref="mongoTypeMapper"></property> </bean> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> <constructor-arg name="mongoConverter" ref="mongoConverter" /> <property name="writeResultChecking" value="EXCEPTION" /> </bean>


Si desea desactivar el atributo _class de forma predeterminada, pero conserva el polimorfismo para las clases especificadas, puede definir explícitamente el tipo de campo _class (opcional) configurando:

@Bean public MongoTemplate mongoTemplate() throws Exception { Map<Class<?>, String> typeMapperMap = new HashMap<>(); typeMapperMap.put(com.acme.domain.SomeDocument.class, "role"); TypeInformationMapper typeMapper1 = new ConfigurableTypeInformationMapper(typeMapperMap); MongoTypeMapper typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Arrays.asList(typeMapper1)); MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()); converter.setTypeMapper(typeMapper); MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter); return mongoTemplate; }

Esto preservará el campo _class (o lo que quieras nombrar en construtor) solo para las entidades especificadas.

También puede escribir el propio TypeInformationMapper basado en anotaciones, por ejemplo. Si anota su documento por @DocumentType("aliasName") mantendrá el polimorfismo al mantener un alias de clase.

Lo he explicado brevemente en mi blog , pero aquí hay un fragmento de código rápido: https://gist.github.com/athlan/6497c74cc515131e1336


Esta es mi solución de una sola línea:

@Bean public MongoTemplate mongoTemplateFraud() throws UnknownHostException { MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName); ((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class return mongoTemplate; }


Mientras que la respuesta de Mkyong aún funciona, me gustaría agregar mi versión de solución ya que algunos bits están en desuso y pueden estar a punto de limpiarse.

Por ejemplo: MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()) está en desuso en favor del new MappingMongoConverter(dbRefResolver, new MongoMappingContext()); y SimpleMongoDbFactory(new Mongo(), "databasename"); a favor de la new SimpleMongoDbFactory(new MongoClient(), database); .

Entonces, mi respuesta final de trabajo sin advertencias de desaprobación es:

@Configuration public class SpringMongoConfig { @Value("${spring.data.mongodb.database}") private String database; @Autowired private MongoDbFactory mongoDbFactory; public @Bean MongoDbFactory mongoDBFactory() throws Exception { return new SimpleMongoDbFactory(new MongoClient(), database); } public @Bean MongoTemplate mongoTemplate() throws Exception { DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory); // Remove _class MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext()); converter.setTypeMapper(new DefaultMongoTypeMapper(null)); return new MongoTemplate(mongoDBFactory(), converter); } }

Espero que esto ayude a las personas que deseen tener una clase limpia sin advertencias de desaprobación.


Luché mucho tiempo con este problema. Seguí el enfoque de mkyong pero cuando introduje un atributo LocalDate (cualquier clase JSR310 de Java 8) recibí la siguiente excepción:

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.time.LocalDate] to type [java.util.Date]

El convertidor correspondiente org.springframework.format.datetime.standard.DateTimeConverters es parte de Spring 4.1 y se hace referencia en Spring Data MongoDB 1.7. Incluso si usé versiones más nuevas, el convertidor no saltó.

La solución era usar el MappingMongoConverter existente y solo proporcionar un nuevo DefaultMongoTypeMapper (el código de mkyong está bajo comentario):

@Configuration @EnableMongoRepositories class BatchInfrastructureConfig extends AbstractMongoConfiguration { @Override protected String getDatabaseName() { return "yourdb" } @Override Mongo mongo() throws Exception { new Mongo() } @Bean MongoTemplate mongoTemplate() { // overwrite type mapper to get rid of the _class column // get the converter from the base class instead of creating it // def converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()) def converter = mappingMongoConverter() converter.typeMapper = new DefaultMongoTypeMapper(null) // create & return template new MongoTemplate(mongoDbFactory(), converter) }

Para resumir:

  • extender AbstractMongoConfiguration
  • anotar con EnableMongoRepositories
  • en mongoTemplate get converter de la clase base, esto garantiza que las clases de conversión de tipos estén registradas