保留关键字插入异常

背景

最近公司的某个应用的监控老是在某段时间报error日志增量过大。

排查过程

到kibana里查下那段时间error日志,发现每天在那段时间,都会抛出下面这段异常

org.springframework.data.mapping.MappingException: Map key ***.*** contains dots but no replacement was configured! Make sure map keys don't contain dots in the first place or configure an appropriate replacement!
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.potentiallyEscapeMapKey(MappingMongoConverter.java:873)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.prepareMapKey(MappingMongoConverter.java:855)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeMapInternal(MappingMongoConverter.java:822)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createMap(MappingMongoConverter.java:743)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:628)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:596)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:572)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:545)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:489)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:94)

大概意思就是key里面包含"."。但是没有配置替代策略。叫我们确认key不包含".",或者配置替代策略。

Documen实体类如下:

@Data
@Accessors(chain = true)
@Document("extend_strategy")
public class ExtendStrategyDo {

    /**
     * 策略id
     */
    @Indexed(unique = true)
    private Integer strategyId;

    /**
     * 调用详情
     */
    private Map<String, InvokeRecord> invokeInfo = new HashMap<>(0);
}

查了一下。发现.$ 是Mongo的保留关键词。字段名内不能包含保留关键词。
虽然我们strategyId和invokeInfo不包含保留关键词。但是对于MongoDB中的键名,同样的限制也适用于Map的键和JSON对象的键。

因此,如果您的Map中的键名包含MongoDB不允许的字符(如点号和美元符号),或者超过了MongoDB的键名长度限制,插入操作可能会失败。

同样地,对于JSON对象的键名,也需要遵循相同的规则。在插入JSON文档时,如果键名不符合MongoDB的限制条件,可能会导致插入失败。

解决方法

将key中的.替换成其他非保留关键词。我们业务中是非必要使用.所以可以直接替换。如果非要使用怎么办呢。

可以在封装一下insertquery方法。插入前检查替换成别的字符。查询的时候替换回.

MongoTemplate Upsert异常

异常

mongo在使用mongoTemplate执行upsert的时候报如下错误:

org.springframework.dao.DataIntegrityViolationException: Performing an update on the path '_id' would modify the immutable field '_id'; nested exception is com.mongodb.MongoWriteException: Performing an update on the path '_id' would modify the immutable field '_id'
at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:112)
at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:2902)\n\tat org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:587)
at org.springframework.data.mongodb.core.MongoTemplate.doUpdate(MongoTemplate.java:1636)
at org.springframework.data.mongodb.core.MongoTemplate.upsert(MongoTemplate.java:1570)

大概意思就是_id是不可变更的,但是你upsert操作变更了_id。所以报了异常。

解决方法

在更新过程中,把_id字段set null,就可以了。