Description
Hi here 👋 ,
What is the issue ?
On my project I want to update a given MongoDB document having properties
map as subdocument.
I'm using org.springframework.data:spring-data-commons:jar:3.1.11
(and spring data mongodb 4.1.11) .
I encounter IllegalArgumentException: Name must not be null or empty
from PropertyPath.java:82
while trying to patch a given document properties
.
Context - How to reproduce ?
- Given a following MongoDB content :
{"_id": .., "name":"docA", "properties": {"bien" : "dd", "OK" : "eee"}}
ℹ️ A usecase - I encounter no issue to set / unset a property having " " space in the beginning of a property key value with a word starting with lowercase; example :
update.set("properties. ooo", "space minus");
or
update.unset("properties. ooo");
(...)
mongoTemplate.findAndModify(query, update, options, documentClass);
ℹ️ B usecase - BUT now if I'm doing the same thing with a word starting with an uppercase, I encounter an issue :
update.set("properties. P", "space Major");
or
update.unset("properties. P");
(...)
mongoTemplate.findAndModify(query, update, options, documentClass);
java.lang.IllegalArgumentException: Name must not be null or empty
stack extract
java.lang.IllegalArgumentException: Name must not be null or empty
at org.springframework.util.Assert.hasText(Assert.java:294)
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:82)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:443)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:476)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:419)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:403)
at org.springframework.data.mapping.PropertyPath.lambda$from$0(PropertyPath.java:375)
at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:354)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.forName(QueryMapper.java:1310)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.getPath(QueryMapper.java:1243)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.<init>(QueryMapper.java:1136)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.<init>(QueryMapper.java:1113)
at org.springframework.data.mongodb.core.convert.UpdateMapper$MetadataBackedUpdateField.<init>(UpdateMapper.java:294)
at org.springframework.data.mongodb.core.convert.UpdateMapper.createPropertyField(UpdateMapper.java:254)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:156)
at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
at org.springframework.data.mongodb.core.convert.QueryMapper.convertSimpleOrDocument(QueryMapper.java:596)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedKeyword(QueryMapper.java:403)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:150)
at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
at org.springframework.data.mongodb.core.QueryOperations$UpdateContext.getMappedUpdate(QueryOperations.java:861)
at org.springframework.data.mongodb.core.MongoTemplate.doFindAndModify(MongoTemplate.java:2698)
at org.springframework.data.mongodb.core.MongoTemplate.findAndModify(MongoTemplate.java:1088)
at org.springframework.data.mongodb.core.MongoTemplate.findAndModify(MongoTemplate.java:1063)
Further analysis
By debugging some test with different value, I can state that spring-data-commons
> PropertyPath
component is processing some part of the update query and will see some field following spring data internal logic :
- for the A use case, ("properties. ooo") only the word
ooo
is detected under properties - for the B use case, ("properties. P") two word
P
and
With mongo Shell, I'm trying to reproduce but no issue, all is fine (usecase B too)
case A OK
db.myDocs.find({"name":"docA"},{"properties":1})
db.myDocs.update({"name":"docA"},{ "$set": {"properties. minus":"blob"}})
db.myDocs.update({"name":"docA"},{ "$unset": {"properties. minus":1}})
case B OK
db.myDocs.update({"name":"docA"},{ "$set": {"properties. Major":"blob"}})
db.myDocs.find({"name":"docA"},{"properties":1})
db.myDocs.update({"name":"docA"},{ "$unset": {"properties. Major":1}})
What did I expect
I expect the update to work like on mongo shell.
I though this is a bug at the PropertyPath layer (but not sure) Or maybe in spring data mongodb?
If this is stated as "not a bug",
I would like to know the recommendation for this kind of update for the "key" value.
Example (mongo manual):
- exclude this words :
class
and_class
, .
is not autorized$
is not autorized as first character
I appreciate some reference to complete this, if any
regards.