問題
@Field("fs")
public Map<String, Integer> favoriteStickers = new LinkedHashMap<>();
使用MongoTemplate
直接為favoriteStickers
欄位新增新值key為STICKER@10002,value為1時,@Field配置的別名不會被成功對映。
mongoTemplate.upsert(query(where("uid").is(1), new Update().set("favoriteStickers.STICKER@10002", 1), UserSticker.class);
原因
MongoTemplate
會將執行語句中的key(上面的 uid
、 favoriteStickers.STICKER@10002
)對映成MongoDB中對應的欄位,如果在UserSticker
類的定義中有相應的配置則會按配置對映。例如問題欄位使用的@Field
就是用來配置別名的。
對於favoriteStickers.12
, 會當作favoriteStickers
是個陣列,12
為被操作的秩,favoriteStickers
屬性在UserSticker
中有定義可以成功對映。
對於favoriteStickers.STICKER@10002
,會當作是有層級關係。即當作favoriteStickers
是一個物件,該物件的定義中有一個STICKER@10002
屬性,如果沒有不做對映。favoriteStickers
是一個map所以無法對映。
重要原始碼
org.springframework.data.mongodb.core.convert.QueryMapper#getMappedObject(org.bson.conversions.Bson, org.springframework.data.mongodb.core.mapping.MongoPersistentEntity<?>)
方法就是直接用來對映物件的,在這個方法中的程式碼Field field = createPropertyField(entity, key, mappingContext);
是用來構建欄位的對映關係。
最終會指向org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getPath(java.lang.String)
這個方法中出問題的就是PropertyPath path = PropertyPath.from(pathExpression.replaceAll("\.\d+", ""), entity.getTypeInformation());
這行程式碼又會呼叫org.springframework.data.mapping.PropertyPath#from(java.lang.String, org.springframework.data.util.TypeInformation<?>)