Basically, I am new to MongoDB and learning from documents. I wanted to use validator, validationLevel, validationAction while defining a collection in MongoDB. So I can get an error if validated data is not inserted or updated. I have followed this document for reference. However, I got success in defining collection but when I add the wrong record it doesn't give me error like it is mentioned in documents. Everytime new record is getting inserted. Can you guys please help me in this whats wrong with my code.
I am using the following command to create a collection
db.createCollection( "contacts",
{
validator: { $and:
[
{ phone: { $type: "string" } },
{ email: { $regex: /#mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
],
validationAction: "error"
}
}
)
I have also used the same command with validationLevel to strict like below but it also didn't work out.
db.createCollection( "contacts",
{
validator: { $and:
[
{ phone: { $type: "string" } },
{ email: { $regex: /#mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
],
validationAction: "error",
validationLevel: "strict"
}
}
)
A command I used to insert record is as below
db.contacts.insert( { name: "Amanda", status: "Updated" } )
Below is the expected output as per the document.
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
But I end up getting success output as below
WriteResult({ "nInserted" : 1 })
I guess you validation rule is not applied to the collection. You can check for the same using
getCollectionInfos({name:'constacts'})
here is the link.
Error is in the validationAction and validationLevel.
use this
db.createCollection( "contacts", { validator:
{ $and:
[
{ phone: { $type: "string" } },
{ email: { $regex: /#mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
]
},
validationLevel : "strict",
validationAction : "error"
}
)
insted of
db.createCollection( "contacts",
{
validator: { $and:
[
{ phone: { $type: "string" } },
{ email: { $regex: /#mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
],
validationAction: "error",
validationLevel: "strict"
}
}
)
Quote from documentation:
You cannot specify a validator for collections in the admin, local,
and config databases. You cannot specify a validator for system.*
collections.
https://docs.mongodb.com/v3.2/reference/method/db.createCollection/
Related
I have the following datastructure
{
_id: ObjectId('61ae12bfb8047effd0ac2a01'),
data: [
{
xml: {
messageId: 1638798015073,
xmlString: 'someXML'
},
data: [
{
customerId: 123456,
validation: {
isValid: true,
message: ''
},
docs: [
{
objectId: 'PA1106:zt:bb302216879669b58c141b12dcdd5eb0',
writtenBack: false
}
]
},
{
customerId: 55555,
validation: {
isValid: true,
message: ''
},
docs: [
{
objectId: 'PA1106:zt:bb302216879669b58b143ef38c016217',
writtenBack: true
}
]
}
]
},
{
xml: {
messageId: 1638798015094,
xmlString: 'someXML'
},
data: [
{
customerId: 55555,
validation: {
isValid: true,
message: ''
},
docs: [
{
objectId: 'PA1106:zt:bb302216879669b58c1416129062c2d2',
writtenBack: false
},
{
objectId: 'PA1106:zt:b8be9ea04011c2a18c148a0d4c9d6aab',
writtenBack: true
}
]
},
]
},
],
createdAt: '2021-12-06T13:40:15.096Z',
createdBy: 'Test'
}
Now I want to update the writtenBack property of for a given Document and objectId. How would I write a query for this?
my updateOne looked like this
{
_id: '61ae12bfb8047effd0ac2a01',
'data.data.docs.objectId': 'PA1106:zt:bb302216879669b58b143ef38c016217'
},
{
$set: { 'data.data.docs.$.writtenBack': true }
}
I know there is arrayFilters for nested arrays, but as far as I know, I need a unique identifier for each array-Level. But I only have the objectId which is unique for a Document. Any Ideas?
Yes, you can achieve the update for the document in the nested array with positional operator $[] and arrayFilters.
db.collection.update({
_id: "61ae12bfb8047effd0ac2a01",
},
{
$set: {
"data.$.data.docs.$[doc].writtenBack": true
}
},
{
arrayFilters: [
{
"doc.objectId": "PA1106:zt:bb302216879669b58b143ef38c016217"
}
]
})
Sample Mongo Playground
I made it work with this query
{
_id: '61ae12bfb8047effd0ac2a01',
},
{
$set: { 'data.$[elem1].data.$[elem2].docs.$[elem3].writtenBack': true }
},
{
arrayFilters: [
{ 'elem1.xml.messageId': 1638798015094 },
{ 'elem2.customerId': 55555},
{ 'elem3.objectId': 'PA1106:zt:bb302216879669b58c1416129062c2d2'}]
}
Basically with this I manage to return all my objects from a collection. How can I return a single element, for example
in the style of findOne({_ id:" 5e82d378527bb420a4001aaf ")?
I know how to use $match, but this returns various results.
let _id="5e82d378527bb420a4001aaf"
Noticia.aggregate([
{
$addFields: {
like: {
$cond: [{ $in: [_id, "$likes"] }, true, false]
},
dislike: {
$cond: [{ $in: [_id, "$dislikes"] }, true, false]
}
}
}
], (err, noticia) => {
// console.log(trans);
if (err) {
return res.status(400).json({
ok: false,
err
});
}
return res.status(200).json({
ok: true,
data: noticia
});
})
Consider a sample names collection:
{ _id: 1, name: "Jack", favoriteColor: "blue" },
{ _id: 2, name: "James", favoriteColor: "red" },
{ _id: 3, name: "John", favoriteColor: "blue" }
and run the following three queries using findOne:
db.names.findOne( { _id: 1 } )
db.names.findOne()
db.names.findOne( { favoriteColor : "blue" } )
the result is same for the three queries:
{ "_id" : 1, "name" : "Jack", "favoriteColor" : "blue" }
The equivalent queries respectively using aggregation are the following, with the same result:
db.names.aggregate( [
{ $match: { _id: 1 } },
] )
db.names.aggregate( [
{ $limit: 1 }
] )
db.names.aggregate( [
{ $match: { "favoriteColor" : "blue" } },
{ $limit: 1 }
] )
db.collection.findOne definition says -
Returns one document that satisfies the specified query criteria on
the collection or view. If multiple documents satisfy the query, this
method returns the first document according to the natural order which
reflects the order of documents on the disk.
With findOne if no document is found it returns a null. But an aggregation returns a cursor, and you can apply the cursor methods on the result.
Just use $limit to limit no.of docs to be returned from aggregation pipeline :
Noticia.aggregate([
{
$addFields: {
like: {
$cond: [{ $in: [_id, "$likes"] }, true, false]
},
dislike: {
$cond: [{ $in: [_id, "$dislikes"] }, true, false]
}
}
} , {$limit :1} // will return first doc from aggregation result of '$addFields' stage
], (err, noticia) => {
// console.log(trans);
if (err) {
return res.status(400).json({
ok: false,
err
});
}
return res.status(200).json({
ok: true,
data: noticia
});
})
Or if you wanted to return random single doc try $sample.
//Express and mongoose
exports.getData = (req, res) => {
Noticia.aggregate([
{
$addFields: {
like: {
$cond: [{ $in: [_id, "$likes"] }, true, false]
},
dislike: {
$cond: [{ $in: [_id, "$dislikes"] }, true, false]
}
}
}
]
).then( data=>{
res.send(data[0]); //return one document in format { ..... }
}).catch(err => {
res.status(500).send({
message: err.message
});
});
}
How do I get the current validator of a mongo collection?
Or is there no way, and I just need to overwrite it?
You can get it with the db.getCollectionInfos() method.
Example:
Create a collection in an empty database:
db.createCollection( "contacts",
{
validator: { $or:
[
{ phone: { $type: "string" } },
{ email: { $regex: /#mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
]
},
validationAction: "warn"
}
)
{ "ok" : 1 }
Run the command:
db.getCollectionInfos()[0].options.validator
Result:
{
"$or" : [
{
"phone": {
"$type": "string"
}
},
{
"email": {
"$regex": /#mongodb\.com$/
}
},
{
"status": {
"$in": [
"Unknown",
"Incomplete"
]
}
}
]
}
The validator is found as an object in the options object.
Trying to test the validation of the document below:
db.createCollection("Users", {
validator: {
$and: [
{
Uid: {
$type: "string",
$exists: true
}
},
{
"Doc.Name": { $type: "string", $exists: true},
"Doc.Files": [
{
"$ref": { $in: [ "fs.files" ] },
"$id": { $type: "objectId", $exists: true },
"$db": { $in: [ "mydb" ] }
}
]
}
]
}
})
With command of insertion:
db.Users.insert({
Uid: "ABCDFE123m",
Doc: {
Name: "12hgf123",
Files: [
{
$ref:"fs.files",
$id: ObjectId("5910e46b24f3f7057c4088a8"),
$db: "mydb"
},
{
$ref:"fs.files",
$id: ObjectId("4010e46b24f3f7057c408806"),
$db: "mydb"
}
]
}
})
I get the following error:
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
Enable to validate the document insertion. Someone can help me? Look like i forget something.
Regards
I recently started working with MongoDB (version 3.2.9) and wanted to try the validation capabilities it had, as I like database-level consistency.
I know I can, and should only, do this validation in the business logic, as I already do.
But it feels nice having an additional layer of security.
I tried adding a collection category with an _id of type 'int', name of type 'string' and desc of type 'string'.
These values should all exist, but restrictions on the content are not given.
Now, following the manual, I ended up with the following code:
db.createCollection('category', {
validator: { $or:
[
{ _id: { $and: [ { $exists: true },
{ $type: 'int' } ] } },
{ name: { $and: [ { $exists: true },
{ $type: 'string' } ] } },
{ desc: { $and: [ { $exists: true },
{ $type: 'string' } ] } }
]
}
})
However, with this simple structure already, MongoDB complains:
{ "ok" : 0, "errmsg" : "unknown operator: $and", "code" : 2 }
Now, I have found this similar question, but just went and tried to put multiple constraints directly inside the $or arrays:
db.createCollection('category', {
validator: { $or:
[
{ _id: { $exists: true } },
{ _id: { $type: 'int' } },
{ name: { $exists: true } },
{ name: { $type: 'string' } },
{ desc: { $exists: true } },
{ desc: { $type: 'string' } }
]
}
})
But now, while it does create the collection like it should, I can now execute any of the following insert commands:
db.category.insert({})
db.category.insert({_id: 17, name: '', desc: 'valid'})
db.category.insert({_id: 42, name: 42, desc: ''})
db.category.insert({_id: 43, name: '', desc: 42})
db.category.insert({_id: '', name: 42, desc: 42})
db.category.find() now returns
{ "_id" : ObjectId("57e19650b10ab85eca323684") }
{ "_id" : 17, "name" : "", "desc" : "valid" }
{ "_id" : 42, "name" : 42, "desc" : "" }
{ "_id" : 43, "name" : "", "desc" : 42 }
{ "_id" : "", "name" : 42, "desc" : 42 }
As a last resort, I tried changing the $or operator to an $and, as it should need all rules to be valid, not just at least one.
db.createCollection('category', {
validator: { $and:
[
{ _id: { $exists: true } },
{ _id: { $type: 'int' } },
{ name: { $exists: true } },
{ name: { $type: 'string' } },
{ desc: { $exists: true } },
{ desc: { $type: 'string' } }
]
}
})
With this approach which seems the most rational to me, it however does not work at all. No matter which of the above mentioned inserts I tried using, mind you there's one valid out of the 5, none works, all giving me the same error:
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
As stated above, a call to db.version() returns 3.2.9, and I am running the default MongoDB 64-bit distribution on a Windows machine with only the --dbpath parameter set to a previously empty directory.
Please provide the 32-bit integer value using the function NumberInt(). Otherwise, it is interpreted as Double.
The following insert should successfully insert a document into collection.
Success scenario:-
db.category.insert({_id: NumberInt(17), name: "aaaa", desc: "valid"})
Failure scenario:-
db.category.insert({_id: NumberInt(42), name: 42, desc: ''})