3

I'm having problems with inserting into mongoDB because good objects don't pass the mongoDB validator.

To make it worse, the error is a generic: Document failed validation which in a big multi-nested object can make things confusing regarding where exactly this validation fails.

myValidatorIs =
  { validator:
      { $jsonSchema :
          { bsonType: "object"
          , required: [ "price" ]
          , properties:
              { price:
                  { bsonType: "double" // price needs to be a double, tried with decimal also.
                  , description: "must be a double/float and is required"
                  }
              }
          }
      }
  , validationAction: "error"
  , validationLevel: "strict"
  };

db.collection("collection").insertOne({ price : 4.5 }); // this works 
db.collection("collection").insertOne({ price : 4.0 }); // this doesn't - see error below

ERROR: UnhandledPromiseRejectionWarning: MongoError: Document failed validation

My app needs something different but i simplified it here by using price.

Now after lots of trial and error i figured out what actually happens. Was not as clear as above.

Basically in javascript the 4.0 (float) is implicitly transformed to 4 (integer) And this integer fails the validation since is not a float. Which is super wired. Since this data comes from outside, i can't control if is float or integer. Javascript only knows about number.

Is this indeed the problem? I mean i tried lots of different things and i can't see any other reason other then this implicit type conversion.

Because in the validator - if i set bsonType : "int" and i give it {price: 1} or {price: 4.0} then the insertion works with no errors.

How to deal with this type of issue? How to insert {price: 4.0}?

Also what settings should i include to make that description field i set to appear in the error message? After all what is the purpose of properties.price.description if not to create better error messages ?

3
  • In terms of JSON Schema, the description field is an annotation only. It's down to the application to determine how to use that. There are a few other annotations which could be used for similar purposes. Hopefully in the near future, we can work with MongoDB to devise their own vocabulary for purposes beyond simply validation of JSON. Sorry I can't help with your specific issue. Commented Sep 5, 2019 at 20:49
  • My understanding is that all numbers are implicitly stored as doubles in MongoDB (see: docs.mongodb.com/manual/core/shell-types/#numberdecimal). Maybe try explicitly setting the number to a float using the NumberDecimal function like: db.collection("collection").insertOne({ price : NumberDecimal(4.0) }); Commented Sep 6, 2019 at 1:44
  • @Ivrf this worked, just that is not exactly what you said, is not the shell-type, found the Double constructor on the mongodb and used that. The answer is below, but this comment helped me get to the solution. Thanks :) Commented Sep 6, 2019 at 16:14

1 Answer 1

5

Found 2 solutions:

1. A somewhat wired approach - because i endup with mixed types in my column. In general, you might not want mixed types since adds complexity - and there is no good reason for them to be considered mixed in my case.

Basically instead of a single type, you can use a list of types like so:

bsonType: "double" vs bsonType: [ "double", "int" ].

This feature is documented here: $types.

myValidatorIs =
  { validator:
      { $jsonSchema :
          { bsonType: "object"
          , required: [ "price" ]
          , properties:
              { price:
                  { bsonType: [ "double", "int" ]  // add "int" in this array here
                  , description: "must be a double/float and is required"
                  }
              }
          }
      }
  , validationAction: "error"
  , validationLevel: "strict"
  };

2. The recommended approach, found this with help from @lvrf

const MongoType_Double = require('mongodb').Double;

myValidatorIs =
  { validator:
      { $jsonSchema :
          { bsonType: "object"
          , required: [ "price" ]
          , properties:
              { price:
                  { bsonType: "double"  // leave this as double
                  , description: "must be a double/float and is required"
                  }
              }
          }
      }
  , validationAction: "error"
  , validationLevel: "strict"
  };

// then use the MongoType_Double constructor like so: 

db.collection("collection").insertOne({ price : MongoType_Double(4.0) }); // no errors..

This should also work for all the other types like timestamp and such:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.