2

I'm using Spring Data with a MongoDB to save some documents. When saving documents, I would like that Mongo does not contain empty objects. (How) can this be achieved?

Say I have the following main class:

@Document(collection = "main_doc")
public class MainDoc {
    @Id
    private String id;

    private String title;
    private SubDoc subDoc;
}

that contains an object of the following class:

public class SubDoc {

    private String title;
    private String info;

}

Now if I would try to save the following object:

MainDoc main = new MainDoc();
main.setTitle("someTitle");
main.setSubDoc(new SubDoc());

Note: in reality I do not control the fact that the SubDoc is set like this. It can either be empty or filled in. What I want is that if an element's properties/fields are all NULL, it will not be stored in mongo at all. This results in something like this in mongo:

{
    "_id" : "5a328f9a-6118-403b-a3a0-a55ce52099f3",
    "title": "someTitle",
    "subDoc": {}
}

What I would like is that if an element contains only null properties, they aren't saved at all, so for the above example I would want the following result:

{
    "_id" : "5a328f9a-6118-403b-a3a0-a55ce52099f3",
    "title": "someTitle"
}

Saving of documents is done with the help of a repository as following:

@NoRepositoryBean
public interface MainRepo extends CrudRepository<MainDoc, String> {

    // save inherited

}

Thanks in advance.

8
  • 1
    Don't call main.setSubDoc(new SubDoc()); You are setting it to empty. If you don't call that then it will not be there. Commented Jun 9, 2017 at 12:19
  • Yes, but in my actual use-case I can't control that part. I really need it to be done during mapping. Sorry, should've been more clear about that. Commented Jun 9, 2017 at 12:20
  • Can you be more specific in your question then? It seems to me that if there is no data to put in there you simply do not make the call. Perhaps you need an if in your code. Commented Jun 9, 2017 at 12:22
  • The thing is that in reality, my object is built from a ton of nested queries to a relational database and then to be saved to a mongo DB. Having to check everytime if the nested object that is used is empty, would mean a ton of checks. That's why I would prefer to let the mapping do the job for me. Commented Jun 9, 2017 at 12:23
  • The place for detail is in your question. Edit Your Question and don't post long comments. Commented Jun 9, 2017 at 12:24

1 Answer 1

2

One thing you can do here is to write your custom converter for MainDoc:

public class MainDocConverter implements Converter<MainDoc, DBObject> {
    @Override
    public DBObject convert(final MainDoc source) {
        final BasicDbObject dbObject = new BasicDBObject();
        ...
        if(/* validate is subdoc is not null and not empty */) {
            dbOject.put("subDoc", source.getSubDoc());
        }
    }
}

You can register it in @Configuration file for example:

@Configuration
@EnableMongoRepositories(basePackages = {"package"})
public class MongoConfig {

    private final MongoDbFactory mongoDbFactory;

    public MongoConfig(final MongoDbFactory mongoDbFactory) {
        this.mongoDbFactory = mongoDbFactory;
    }

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {

        final MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, getDefaultMongoConverter());
        return mongoTemplate;

    }

    @Bean
    public MappingMongoConverter getDefaultMongoConverter() throws Exception {

        final MappingMongoConverter converter = new MappingMongoConverter(
                new DefaultDbRefResolver(mongoDbFactory), new MongoMappingContext());
        converter.setCustomConversions(new CustomConversions(Arrays.asList(new MainDocConverter())));

        return converter;
    }

}

If you don't want to write a custom converter for your object toy can use default one and and modify it a bit.

final Document document = (Document) getDefaultMongoConverter().convertToMongoType(mainDoc);

if(/* validate is null or is empty */) {
    document .remove("subDoc");
}

mongoTemplate().save(document);

Actually it's not the best way. As guys wrote empty object should be stored as {}, but converter can help you with your case.

Sign up to request clarification or add additional context in comments.

2 Comments

That would get me what I want yes, but it would still require a lot of checks. Would there be a way to, from that custom converter, first call the default implementation and then check if the dbObject has no fields set and return null in that case?
@CounterFlame I've edited my answer. You can use default converter for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.