Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose Schema vs Mongo Validator

Mongo 3.2 have document validation, can we use the same to define a schema instead of using mongoose to do so.? For example :

Mongoose

userschema = mongoose.Schema({
   org: String,
   username: String,
   fullname: String, 
   password: String,
   email: String
});

MongoDB

db.createCollection(
   "example",{
     validator:{
       $and:[
         { "org":{$type:"string"}},
         { "username":{$type:"string"}},
         { "fullname":{$type:"double"}},
         {"password":$type:"string"}},
         {"email":{$type:"string"}}
       ]
     }, 
     validationLevel:"strict",
     validationAction:"error"
 })

What ar ethe difference between these tow and can we provide an optional field using validator as in schema ?

like image 699
Saurabh Verma Avatar asked Apr 06 '16 01:04

Saurabh Verma


People also ask

Should I use Mongoose or MongoDB?

Mongoose is not the only ODM library, there are hapijs/joi, MongoDB schemas, etc. And while Mongoose is good especially in areas of inferring data types, we should choose to use the MongoDB schema validation for schemas validation.

What is the difference between Mongoose and MongoDB?

Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node. js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB. MongoDB is a schema-less NoSQL document database.

Does MongoDB support schema validation?

MongoDB has a feature called schema validation that allows you to apply constraints on your documents' structure. Schema validation is built around JSON Schema, an open standard for JSON document structure description and validation.

What is validator in Mongoose?

Validation is middleware. Mongoose registers validation as a pre('save') hook on every schema by default. You can disable automatic validation before save by setting the validateBeforeSave option. You can manually run validation using doc. validate(callback) or doc.


2 Answers

I use both because they each have different limitations:

  • Mongoose validators do not run on all types of update queries, and validators only run on paths with values in the update doc because the validators can't know if, for example, a required field is already defined in the database but not in your client's memory (see issue). This is a major reason to use MongoDB validators [in addition to Mongoose validators].

    update validators only run on $set and $unset operations (and $push and $addToSet in >= 4.8.0).

    So you can have a field with required: true in your Mongoose schema, but an update operation will not actually require that field! A MongoDB validator can solve this:

      db.runCommand({collMod: "collection", validator: {myfield: {$exists: true}}})
    
  • MongoDB for the most part cannot reference other fields during validation. For example, you can't say {field1: {$lte: field2}}. Mongoose validators can reference other fields.

    You can do some very basic types of cross-field referencing though:

      {validator: {myfield1: "Value 1", $and: [/* other validators */]}
    

    This comes in handy if you're using Mongoose discriminators (inheritance) and have different requirements for each child type.

  • MongoDB does not provide "nice" errors in case of validation failure; it simply says something like writeError: {code: 121, errmsg: "Document failed validation}. Mongoose will typically say something like Path 'foo.bar' failed validation.

    MongoDB is fixing this in v4.6.

Abilities that they share:

  • Type validation. Mongoose by default attempts to cast values to the type specified in the schema. MongoDB with the $type attribute will cause a validation failure in case of a type mismatch.

  • Min and max number values. Mongoose uses min and max attributes on the schema. MongoDB uses $lt, $lte, $gt and $gte.

  • String enums. Mongoose uses enum: [values]. MongoDB uses $in: [values].

  • String length validation. Mongoose: minlength: 2, maxlength: 10. MongoDB, use a regex: {fieldname: {$regex: /.{2,10}/}}.

  • Array length validation. Mongoose you have to use a custom validator. MongoDB: {fieldName: {$size: 2}}.

  • String RegExp matching. Mongoose you have to use a custom validator.


The first bullet point is a major one. MongoDB does not have transactionsnow has transactions, but it does have powerful (and cheap) atomic updates. You often times can't reliably or safely read -> change -> validate -> write with MongoDB, so using MongoDB native validators is critical in these cases.

like image 68
ZachB Avatar answered Oct 22 '22 03:10

ZachB


Since the last answer, MongoDB 4.0 have been released.

the $jsonSchema feature now have more options than base mongoose Schema validator. (you can add custom validator in mongoose, though). the use of allOf, oneOf, anyOf and not operator permit to do complex matching, similar to Mongoose discriminator.

with the $exec command, it is possible to compare the value of two field of the same document like so :

db.createCollection("test", {
    validator : {
        $expr : {$gte: ["$budget", "$spend"]}
    }
})

will validate that the value of the field budget must be greater or equal than the value of spend.

(example adapted from mongodb documentation)

MongoDB still have the problem of non informative error message. Personnally, I validate my data client side (making request to database if necessary to check for uniqueness). This way, the validation of mongodb have error only if there is concurent modification (someone modified the data between the moment you check and the moment you save). when there is mongodb error, I can simply rerun the client side validation to see what wrong.

I think Mongoose is used to it's fullest when used with a find-modify-save strategy, witch permit to use all the feature. this strategy need the use of versioning or locking to prevent concurrent modification.

when going for atomic update (using mongodb operator, update or findAndModify), with the current state of mongodb validation, I would be tempted to not use mongoose (or only use it for the connection management)

like image 45
Félix Brunet Avatar answered Oct 22 '22 02:10

Félix Brunet