mongo_orm Exception: missing bson key: publish_acl (Exception)

When you extend your field definitions in the mongo_orm document classes, specifically with embedded documents, you might run into the following runtime (!) error:

Exception: missing bson key: <name> (Exception)

This is not an error in your code – your code is raising, because the database structure is not as it expects it to be!

Here’s the sample code which I am using for creating a Mongo Auth & ACL DB for VerneMQ:

class PublishACL < Mongo::ORM::EmbeddedDocument
     field pattern : String
     field max_qos : Int32
     field allowed_retain : Bool
     field max_payload_size : Int32
end

class SubscribeACL < Mongo::ORM::EmbeddedDocument
     field pattern : String
     field max_qos : Int32
end

class MQTTCredentials < Mongo::ORM::Document
     collection_name “vmq_acl_auth”
     field mountpoint : String
     field client_id : String
     field username : String
     field passhash : String
     embeds_many :publish_acl, class_name: Papi::PublishACL 
     embeds_many :subscribe_acl, class_name: Papi::SubscribeACL

# keys are unique per apikey_prefix
def self.getcredentials(apikey_prefix : String, bcm_serial : String)
     success = false
     #if the credentials don’t exist yet, they are added
     creds = self.first({“client_id” => bcm_serial, “username” => apikey_prefix})
     if !creds
         creds = self.new()
     end

     (snip)

    publish_acl = PublishACL.new()
     subscribe_acl = SubscribeACL.new()
     # https://vernemq.com/docs/configuration/db-auth.html
     publish_acl.pattern = “#”
     publish_acl.max_qos = 2  # Int
     publish_acl.allowed_retain = true

    subscribe_acl.pattern = “#”
     subscribe_acl.max_qos = 2
    
     creds.publish_acl <<  publish_acl
     creds.subscribe_acl << subscribe_acl 
     success = creds.save

(snip)

end

end

The ACLs were inserted after I already had database entries without them:

image

MongoORM error message:

Exception: missing bson key: publish_acl (Exception)
   from src/db.cr:0:4 in ‘from_bson’
   from lib/mongo_orm/src/mongo_orm/querying.cr:93:7 in ‘all’
   from lib/mongo_orm/src/mongo_orm/querying.cr:90:3 in ‘all’

  (snip)

  from /usr/share/crystal/src/fiber.cr:47:34 in ‘->’
   from ???

MongoORM does not find the expected fields publish_acl and subscribe_acl, which were added later.

Solution: drop (or upgrade) the documents in the Collection, which do not conform to your new standard.

This is, for instance, how a database entry looks like for the above:

image

Bonus

in lib/mongo_orm/src/mongo_orm/extended_bson.cr:40: no overload matches ‘BSON#[]=’ with types String, Array(Papi::PublishACL)

Overloads are:

– BSON#[]=(key, value : Int32)

– BSON#[]=(key, value : Int64)

– BSON#[]=(key, value : Binary)

– BSON#[]=(key, value : Bool)

– BSON#[]=(key, value : Float64 | Float32)

– BSON#[]=(key, value : MinKey)

– BSON#[]=(key, value : MaxKey)

– BSON#[]=(key, value : Nil)

– BSON#[]=(key, value : ObjectId)

– BSON#[]=(key, value : String)

– BSON#[]=(key, value : Symbol)

– BSON#[]=(key, value : Time)

– BSON#[]=(key, value : Timestamp)

– BSON#[]=(key, value : Code)

– BSON#[]=(key, value : BSON)

– BSON#[]=(key, value : Regex)

– BSON#[]=(key, value : Mongo::ORM::EmbeddedDocument)

bson[_key] = value

You cannot do this (currently) with MongoORM:

creds.publish_acl = [ publish_acl ]

instead you have to use:

creds.publish_acl <<  publish_acl