Spring-data-mongo update null value in document using MappingMongoConverter

With spring data mongo, I need to update a document in mongo.

My essence defines the following:

@Document(collection = "Orders")
public class Order{

    @Id
    private Long id;
    private String clientContainerReference;
    private String status;
    private Bigdecimal amount;
    private BigDecimal remainingQuantity;
    ...
}

      

First, this document is inserted into mongo with a remainder of the Quantity of 100. The order is then updated with a remainder of zero. After an update (upsert), the rest of theQuantity is always set to 100.

This is related to the class:

org.springframework.data.mongodb.core.convert.MappingMongoConverter

      

in the writeInternal method, a null check is performed on each document property. If the property is null, it is excluded from the generated DBObject.

entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
        public void doWithPersistentProperty(MongoPersistentProperty prop) {

            if (prop.equals(idProperty)) {
                return;
            }

            Object propertyObj = wrapper.getProperty(prop);

            if (null != propertyObj) {

                if (!conversions.isSimpleType(propertyObj.getClass())) {
                    writePropertyInternal(propertyObj, dbo, prop);
                } else {
                    writeSimpleInternal(propertyObj, dbo, prop);
                }
            }
        }
    });

      

I can understand that it is more efficient because it generates less DBObject and the update request is more digest for mongo. But how can I update real NULL values?

More specifically, in my case, all fields of the entire document may be empty. so I don't want to write my own converter and map one by one to each explicit field in the DBObject field.

For more of my use, I created a "NullAwareMappingMongoConverter" that overrides MappingMongoConverter so that the converter can write the value if it is null.

entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
        public void doWithPersistentProperty(MongoPersistentProperty prop) {

            if (prop.equals(idProperty)) {
                return;
            }


            Object propertyObj = wrapper.getProperty(prop);

            if (null != propertyObj) {

                if (!conversions.isSimpleType(propertyObj.getClass())) {
                    writePropertyInternal(propertyObj, dbo, prop);
                } else {
                    writeSimpleInternal(propertyObj, dbo, prop);
                }
            }
            else{
                writeSimpleInternal(propertyObj, dbo, prop);
            }
        }
    });

      

This is a very dangerous solution because MappingMongoConverter For spring data mongo has package visibility. Does spring provide a way to say don't ignore the null value for this property using annotation or something?

thank

here is the code used to update the object

 public T setNotificationDateAndSave(T entity) {
    Assert.notNull(entity, "Entity must not be null!");
    BasicDBObject dbObject = new BasicDBObject();
    mongoTemplate.getConverter().write(entity, dbObject);

    DateTime expirationDate = getDeprecatedStatus().contains(getStatus(entity)) ?
            new DateTime().plusSeconds(EXPIRE_AFTER_SECONDS) : null;

    dbObject.put(EXPIRATION_DATE_COLUMN, mongoTemplate.getConverter()
            .convertToMongoType(expirationDate, ClassTypeInformation.from(DateTime.class)));


    NotificationDateUpdate update = new NotificationDateUpdate(dbObject, NOTIFICATION_DATE_COLUMN);
    Query q = Query.query(Criteria.where("_id").is(entity.getId()).andOperator(Criteria.where(REGISTER_DATE_COLUMN).lte(entity.getRegisterDate())));
    try{
        mongoTemplate.upsert(q, update, parameterClass);
    }catch (DuplicateKeyException e) {
        logger.info(format("could not save notification : a more recent notification exists for collection %s and entity id : %s", parameterClass.getName(), entity.getId()));
    }
    return entity;
}

      

+4


source to share


1 answer


Same problem, but I didn't want to mess with the converter, it was too complex for needs. I just automated resetting all empty fields for my object.

Slightly adapted to your code, it looks like this:



DBObject dbObject = new BasicDBObject();
mongoTemplate.getConverter().write(entity, dbObject);
Update update = Update.fromDBObject(dbObject);
for (Field f : entity.class.getDeclaredFields()) {
  try {
     f.setAccessible(true);
     if (f.get(entity) == null)
        update.unset(f.getName());
  } catch (IllegalAccessException e) {
     e.printStackTrace();
  }
}
ops.upsert(query,update);

      

0


source







All Articles