Vous ne pouvez utiliser que le $ opérateur positionnel pour les tableaux à un seul niveau. Dans votre cas, vous avez un tableau imbriqué (heros est un tableau, et à l'intérieur de celui-ci chaque héros a un spells tableau).
Si vous connaissez les index des tableaux, vous pouvez utiliser des index explicites lors d'une mise à jour, comme :
> db.test.update({"heros.nickname":"test", "heros.spells.spell_id":1}, {$set:{"heros.0.spells.1.level":3}});