Skip to content

Using $set with nested integer keys breaks the structure #3775

Closed
@zeapo

Description

@zeapo

Given the following class (kotlin)

@Document(collection = "nested_hell")
@TypeAlias("hell")
data class NestedHell(
    @Id val eyeDee: String,
    val levelOne: HashMap<String, HashMap<String, HashMap<String, Any>>>
)

Update queries where the keys in these nested hashmaps are integers, will not go deeper than the second level:

        ops.save(
            NestedHell(
                eyeDee = "id1",
                levelOne = hashMapOf("0" to hashMapOf("1" to hashMapOf("2" to 3)))
            )
        )
        val updateQuery = Update().set("levelOne.0.1.3", 4)
        println(updateQuery.updateObject.toJson())
        ops.updateFirst(
            Query(NestedHell::eyeDee isEqualTo "id1"),
            updateQuery,
            NestedHell::class.java
        )

The result of the save is:

{
        "_id" : "id1",
        "levelOne" : {
                "0" : {
                        "1" : {
                                "2" : 3
                        }
                }
        },
        "_class" : "hell"
}

The update query object is:

{"$set": {"levelOne.0.1.3": 4}}

The result given by the updateFirst is however

{ "_id" : "id1", "levelOne" : { "0" : 4 }, "_class" : "hell" }

Notice that the level "levelOne.0.1" has gone.

Doing the same thing in Mongo Shell gives the expected result:

> db.nested_hell.findOne()
{
        "_id" : "id1",
        "levelOne" : {
                "0" : {
                        "1" : {
                                "2" : 3
                        }
                }
        },
        "_class" : "hell"
}
> db.nested_hell.update({_id: 'id1'}, {"$set": {"levelOne.0.1.3": 4}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.nested_hell.findOne()
{
        "_id" : "id1",
        "levelOne" : {
                "0" : {
                        "1" : {
                                "2" : 3,
                                "3" : 4
                        }
                }
        },
        "_class" : "hell"
}

When using non-numeric keys, the result is as one would expect:

        ops.save(
            NestedHell(
                eyeDee = "id2",
                levelOne = hashMapOf("a" to hashMapOf("b" to hashMapOf("c" to "d")))
            )
        )
        val updateQueryTwo = Update().set("levelOne.a.b.d", "e")
        println(updateQueryTwo.updateObject.toJson())
        val modified = ops.updateFirst(
            Query(NestedHell::eyeDee isEqualTo "id2"),
            updateQueryTwo,
            NestedHell::class.java
        )

Gives

{ "_id" : "id2", "levelOne" : { "a" : { "b" : { "c" : "d", "d" : "e" } } }, "_class" : "hell" }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions