26

When inserting data into MongoDB Spring Data is adding a custom "_class" column, is there a way to eliminate the "class" column when using Spring Boot & MongoDB?

Or do i need to create a custom type mapper?

Any hints or advice?

Marco
  • 15,101
  • 33
  • 107
  • 174
  • 1
    possible duplicate of [Spring data MongoDb: MappingMongoConverter remove \_class](http://stackoverflow.com/questions/6810488/spring-data-mongodb-mappingmongoconverter-remove-class) – Athlan Sep 21 '15 at 19:45

12 Answers12

20

Dave's answer is correct. However, we generally recommend not do this (that's why it's enabled by default in the first place) as you effectively throw away to persist type hierarchies or even a simple property set to e.g. Object. Assume the following type:

@Document
class MyDocument {

  private Object object;
}

If you now set object to a value, it will be happily persisted but there's no way you can read the value back into it's original type.

Oliver Drotbohm
  • 80,157
  • 18
  • 225
  • 211
  • Thanks for the extra details @Oliver, at first I believed _class was useless but with the "magic" that Spring Data provides it makes more sense now. – Jeach Mar 29 '15 at 15:44
  • 1
    @Oliver: Though I see how your point is important in general, there is one exception to it, which is a main use-case I think. If one has a MongoRepository which maps to the collection (and hopefully said one is not dumb enough to shoot his own foot by mapping anything else to that collection), and T is not abstract and no inheriting classes are used with ```@Entity```, then I defeinitely should be able to remove _class without compromising that repo's ability to hydrate a T correctly. Do you agree, or are there other obstacles I overlooked? – Levente Pánczél Jul 18 '20 at 00:22
18

A more up to date answer to that question, working with embedded mongo db for test cases: I quote from http://mwakram.blogspot.fr/2017/01/remove-class-from-mongo-documents.html

Spring Data MongoDB adds _class in the mongo documents to handle polymorphic behavior of java inheritance. If you want to remove _class just drop following Config class in your code.

package com.waseem.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@Configuration
public class MongoConfig {

 @Autowired MongoDbFactory mongoDbFactory;
 @Autowired MongoMappingContext mongoMappingContext;

 @Bean
 public MappingMongoConverter mappingMongoConverter() {

  DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
  MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
  converter.setTypeMapper(new DefaultMongoTypeMapper(null));

  return converter;
 }
}
Jeremie
  • 1,267
  • 12
  • 33
  • Hello, I am getting - `Error creating bean with name 'mongoDBConfig': Unsatisfied dependency expressed through field 'mongoDbFactory'` – iamcrypticcoder Mar 25 '23 at 20:55
  • Change `mongoDbFactory` to `mongoDatabaseFactory` and update the import to `org.springframework.data.mongodb.MongoDatabaseFactory` – rishimaharaj Jul 13 '23 at 16:43
11

Here is a slightly simpler approach:

@Configuration
public class MongoDBConfig implements InitializingBean {

    @Autowired
    @Lazy
    private MappingMongoConverter mappingMongoConverter;

    @Override
    public void afterPropertiesSet() throws Exception {
        mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
    }
}
RZet
  • 914
  • 9
  • 11
8

I think you need to create a @Bean of type MongoTemplate and set the type converter explicitly. Details (non-Boot but just extract the template config): http://www.mkyong.com/mongodb/spring-data-mongodb-remove-_class-column/

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
8

You can remove the _class by following code. You can use this in your mongo configuration class.

@Bean
    public MongoTemplate mongoTemplate(MongoDatabaseFactory databaseFactory, MappingMongoConverter converter) {
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return new MongoTemplate(databaseFactory, converter);
    }
Srinithi K
  • 81
  • 1
  • 4
3

Similar to RZet but avoids inheritance:

@Configuration
public class MongoConfiguration {

    @Autowired
    private MappingMongoConverter mappingMongoConverter;

    // remove _class
    @PostConstruct
    public void setUpMongoEscapeCharacterConversion() {
        mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
    }

}
awgtek
  • 1,483
  • 16
  • 28
1

A simple way (+ for ReactiveMongoTemplate):

  @Configuration
  public class MongoDBConfig {

    @Autowired
    private MongoClient mongoClient;

    @Value("${spring.data.mongodb.database}")
    private String dbName;

    @Bean
    public ReactiveMongoTemplate reactiveMongoTemplate() {
      ReactiveMongoTemplate template = new ReactiveMongoTemplate(mongoClient, dbName);
      MappingMongoConverter converter = (MappingMongoConverter) template.getConverter();
      converter.setTypeMapper(new DefaultMongoTypeMapper(null));
      converter.afterPropertiesSet();
      return template;
    }
  }
Abdelhafid
  • 799
  • 7
  • 13
0

Add a converter to remove class.

MappingMongoConverter converter =
        new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
    converter.setTypeMapper(new DefaultMongoTypeMapper(null));

MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);

    return mongoTemplate;

`

Ashish
  • 11
  • 1
  • 6
0

The correct answer above seems to be using a number of deprecated dependencies. For example if you check the code, it mentions MongoDbFactory which is deprecated in the latest Spring release. If you happen to be using MongoDB with Spring-Data in 2020, this solution seems to be older. For instant results, check this snippet of code. Works 100%. Just Create a new AppConfig.java file and paste this block of code. You'll see the "_class" property disappearing from the MongoDB document.

package com.reddit.redditmain.Configuration;

import org.apache.naming.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@Configuration
public class AppConfig {

@Autowired
MongoDatabaseFactory mongoDbFactory;
@Autowired
MongoMappingContext mongoMappingContext;

@Bean
public MappingMongoConverter mappingMongoConverter() {

    DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
    MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
    converter.setTypeMapper(new DefaultMongoTypeMapper(null));

    return converter;
    }

}
0
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDatabaseFactory; 
import org.springframework.data.mongodb.core.MongoTemplate;
import 
org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import 
org.springframework.data.mongodb.core.convert.MappingMongoConverter;

@Configuration
public class MongoConfigWithAuditing {

 @Bean
 @Primary
 public MongoTemplate mongoTemplate(MongoDatabaseFactory 
 mongoDatabaseFactory, MappingMongoConverter mappingMongoConverter) {

  // this is to avoid saving _class to db
  mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));

  MongoTemplate mongoTemplate = new MongoTemplate(mongoDatabaseFactory, mappingMongoConverter);
  return mongoTemplate;
 }

}
Mounika Bathina
  • 123
  • 4
  • 13
0

Spring Boot 3 with reactive mongo.

package es.dmunozfer.trading.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@EnableReactiveMongoRepositories("es.dmunozfer.trading.repository")
public class MongoConfig extends AbstractReactiveMongoConfiguration {

    @Autowired
    private MongoProperties mongoProperties;

    @Override
    protected String getDatabaseName() {
        return mongoProperties.getDatabase();
    }

    @Bean
    @Override
    public MappingMongoConverter mappingMongoConverter(ReactiveMongoDatabaseFactory databaseFactory, MongoCustomConversions customConversions,
            MongoMappingContext mappingContext) {
        MappingMongoConverter converter = super.mappingMongoConverter(databaseFactory, customConversions, mappingContext);
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return converter;
    }
}
dmunozfer
  • 550
  • 1
  • 5
  • 16
0

I'm leaving this answer here in case someone wants to remove the _class from kotlin and update it a bit since the previous answers have several deprecated dependencies.

import org.springframework.beans.factory.BeanFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.mongodb.MongoDatabaseFactory
import org.springframework.data.mongodb.core.convert.DbRefResolver
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper
import org.springframework.data.mongodb.core.convert.MappingMongoConverter
import org.springframework.data.mongodb.core.mapping.MongoMappingContext


@Configuration
internal class SpringMongoConfig {

    @Bean
    fun mappingMongoConverter(
        factory: MongoDatabaseFactory, context: MongoMappingContext,
        beanFactory: BeanFactory
    ): MappingMongoConverter {
        val dbRefResolver: DbRefResolver = DefaultDbRefResolver(factory)
        val mappingConverter = MappingMongoConverter(dbRefResolver, context)
        mappingConverter.setTypeMapper(DefaultMongoTypeMapper(null))
        return mappingConverter
    }
}
Orelvis15
  • 306
  • 4
  • 11