Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-31402

Document validator fails to reject invalid values in array member

    • ALL
    • Hide
      > db.createCollection('testio', {
      ...   validator: { $or: [
      ...     { dbRefsMember: { $exists: false } },
      ...     {
      ...       $and: [
      ...         { dbRefsMember: { $type: 'object' } },
      ...         { 'dbRefsMember._id': { $exists: false } }
      ...       ]
      ...     }
      ...   ] }
      ... });
      { "ok" : 1 }
      > db.testio.insert({existsFalseValidatesThis:'asItShould'})
      WriteResult({ "nInserted" : 1 })
      > db.testio.insert({dbRefsMember:[{_id: 1, thisGuy: 'shouldAndWillBeRejected'}]})
      WriteResult({
      	"nInserted" : 0,
      	"writeError" : {
      		"code" : 121,
      		"errmsg" : "Document failed validation"
      	}
      })
      > db.testio.insert({dbRefsMember:[false, {_id: 1, thisGuy: 'shouldAndWillAlsoBeRejected'}]})
      WriteResult({
      	"nInserted" : 0,
      	"writeError" : {
      		"code" : 121,
      		"errmsg" : "Document failed validation"
      	}
      })
      > db.testio.insert({dbRefsMember:[1, {thisGuy: 'shouldButWillNotBeRejected'}]})
      WriteResult({ "nInserted" : 1 })
      > db.testio.insert({more:1})
      WriteResult({ "nInserted" : 1 })
      > db.testio.update({more:1}, {$set: {dbRefsMember: []}})
      WriteResult({
      	"nMatched" : 0,
      	"nUpserted" : 0,
      	"nModified" : 0,
      	"writeError" : {
      		"code" : 121,
      		"errmsg" : "Document failed validation"
      	}
      })
      > db.testio.update({more:1}, {$set: {dbRefsMember: [1]}})
      WriteResult({
      	"nMatched" : 0,
      	"nUpserted" : 0,
      	"nModified" : 0,
      	"writeError" : {
      		"code" : 121,
      		"errmsg" : "Document failed validation"
      	}
      })
      > db.testio.update({more:1}, {$set: {dbRefsMember: [DBRef('something', ObjectId())]}})
      WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
      > db.testio.update({more:1}, {$push: {dbRefsMember: 1}})
      WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
      > db.testio.update({more:1}, {$push: {dbRefsMember: false}})
      WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
      > db.testio.update({more:1}, {$push: {dbRefsMember: {_id: 'anotherViolationButThisTimeNotOnTheType'}}})
      WriteResult({
      	"nMatched" : 0,
      	"nUpserted" : 0,
      	"nModified" : 0,
      	"writeError" : {
      		"code" : 121,
      		"errmsg" : "Document failed validation"
      	}
      })
      > db.testio.findOne({more:1})
      {
      	"_id" : ObjectId("59d63137f402d1a9c67ea8ef"),
      	"more" : 1,
      	"dbRefsMember" : [
      		DBRef("something", ObjectId("59d63164f402d1a9c67ea8f0")),
      		1,
      		false
      	]
      }
      > db.testio.insert({more:2}, {$set: {dbRefsMember: [1,2,3,false,'aString',DBRef('something', ObjectId())]}})
      WriteResult({ "nInserted" : 1 })
      
      Show
      > db.createCollection( 'testio' , { ... validator: { $or: [ ... { dbRefsMember: { $exists: false } }, ... { ... $and: [ ... { dbRefsMember: { $type: 'object' } }, ... { 'dbRefsMember._id' : { $exists: false } } ... ] ... } ... ] } ... }); { "ok" : 1 } > db.testio.insert({existsFalseValidatesThis: 'asItShould' }) WriteResult({ "nInserted" : 1 }) > db.testio.insert({dbRefsMember:[{_id: 1, thisGuy: 'shouldAndWillBeRejected' }]}) WriteResult({ "nInserted" : 0, "writeError" : { "code" : 121, "errmsg" : "Document failed validation" } }) > db.testio.insert({dbRefsMember:[ false , {_id: 1, thisGuy: 'shouldAndWillAlsoBeRejected' }]}) WriteResult({ "nInserted" : 0, "writeError" : { "code" : 121, "errmsg" : "Document failed validation" } }) > db.testio.insert({dbRefsMember:[1, {thisGuy: 'shouldButWillNotBeRejected' }]}) WriteResult({ "nInserted" : 1 }) > db.testio.insert({more:1}) WriteResult({ "nInserted" : 1 }) > db.testio.update({more:1}, {$set: {dbRefsMember: []}}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 121, "errmsg" : "Document failed validation" } }) > db.testio.update({more:1}, {$set: {dbRefsMember: [1]}}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 121, "errmsg" : "Document failed validation" } }) > db.testio.update({more:1}, {$set: {dbRefsMember: [DBRef( 'something' , ObjectId())]}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.testio.update({more:1}, {$push: {dbRefsMember: 1}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.testio.update({more:1}, {$push: {dbRefsMember: false }}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.testio.update({more:1}, {$push: {dbRefsMember: {_id: 'anotherViolationButThisTimeNotOnTheType' }}}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 121, "errmsg" : "Document failed validation" } }) > db.testio.findOne({more:1}) { "_id" : ObjectId( "59d63137f402d1a9c67ea8ef" ), "more" : 1, "dbRefsMember" : [ DBRef( "something" , ObjectId( "59d63164f402d1a9c67ea8f0" )), 1, false ] } > db.testio.insert({more:2}, {$set: {dbRefsMember: [1,2,3, false , 'aString' ,DBRef( 'something' , ObjectId())]}}) WriteResult({ "nInserted" : 1 })

      Hi

      I was trying to add document validation to avoid an issue with our software where a document, containing an array of DBRefs was saved back with those DBRefs resolved to their foreign documents. In other words, to validate that the items in this array member are indeed DBRefs.

      As DBRef is not available as a $type to check against, I had to get creative and instead opted for this not-exactly-foolprof idea: Either, the member must not exist, or it must be an array of objects which does not have an _id property.

      In my testing, it becomes clear that it stops rejecting invalid updates once the array contains one valid member. In essence, the validator seems to say, "yep, everything okay" so long as the validator rule, if used as a query, would yield the document being validated.

      I don't see this behavior mentioned anywhere in the docs, so I'm thinking it's a bug. Please see my steps to reproduce for clarification.

            Assignee:
            Unassigned Unassigned
            Reporter:
            Daniel Smedegaard Buus Daniel Smedegaard Buus [X]
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: