I'm starting to use MongoDB node driver and I can't get validation to work at all.
I created the following validation objects using query:
validator: { $in: [
{ name: { $type: "string" } }
]}
And this JSON Schema:
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name"],
properties: {
name: {
bsonType: "string",
description: "is required and must be a string"
}
}
}
}
Then if I try to insert the following document with this structure {name: 2}, it gets added no failed validation whatsoever.
I've read the mongo and the node driver docs up and down regarding document validation and can't find a way to get this validated. I'm currently using Mongo version 3.6.7 and the node driver version 3.1.4, on an express server version 4.16.3.
This is the whole code:
// create a single user
const createSingleUser = (client, db) => {
db.collection("users").insertOne({
name: 2
}, (err, response) => {
if (err) console.warn(err);
console.log("new user added!!!!");
client.close();
}); // insert one
};
// create collection and add validator
const createUserCollection = client => {
const MongoDriverData = client.db("MongoDriverData");
// create the collection and add validation
MongoDriverData.createCollection( "users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name"],
properties: {
name: {
bsonType: "string",
description: "is required and must be a string"
}
}
}
}, // validator
validationAction: "error"
}, (err, results) => {
console.log( "Collection created!!!" );
// now insert a user
createSingleUser(client, MongoDriverData);
});
};
Related
I've got a head-scratcher here that I'd like to share with you all.
So here's the model:
_id: ObjectId()
name: String,
columns: [
{
name: String,
_id: ObjectId()
tasks: [
{
title: String,
description: String,
status: String,
_id: ObjectId()
subtasks: [
{
title: String,
isCompleted: Boolean,
},
],
},
],
},
],
});
and the query:
exports.createSubtask = (req, res) => {
if (!req.body) {
res.status(400).send({ message: "Task name can not be empty!" });
return;
}
const board = req.params.board;
const column = req.params.column;
const task = req.params.task;
Board.findOneAndUpdate(
{
_id: board,
"columns._id": column,
"columns.tasks._id": task,
},
{
$push: {
"columns.$.tasks.$.subtasks": req.body,
},
}
)
.then((data) => {
if (!data) {
res.status(404).send({
message: `Cannot update Task with id=${task}. Maybe task was not found!`,
});
} else res.send({ message: "Task was updated successfully." });
})
.catch((err) => {
res.status(500).send({
message: "Error updating Task with id=" + task,
});
});
};
I'm trying to push an object into the subtasks array with $push, but Postman is throwing an error.
Any ideas as to what I'm doing wrong? Appreciate the help.
Golden Ratio
However, I was able to successfully push an object into the tasks array with the following query:
exports.createTask = (req, res) => {
if (!req.body) {
res.status(400).send({ message: "Task name can not be empty!" });
return;
}
const board = req.params.board;
const column = req.params.column;
Board.findOneAndUpdate(
{
_id: board,
"columns._id": column,
},
{
$push: {
"columns.$.tasks": req.body,
},
}
)
.then((data) => {
if (!data) {
res.status(404).send({
message: `Cannot update Column with id=${column}. Maybe column was not found!`,
});
} else res.send({ message: "Column was updated successfully." });
})
.catch((err) => {
res.status(500).send({
message: "Error updating Column with id=" + column,
});
});
};
It is not possible to use multiple positional $ for the nested array as mention in docs:
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value
You should work with the positional filtered operator $[<identifier>].
Board.findOneAndUpdate(
{
_id: board,
"columns._id": column,
"columns.tasks._id": task,
},
{
$push: {
"columns.$.tasks.$[task].subtasks": req.body,
},
},
{
arrayFilters: [
{ "task._id": task }
]
}
)
.then(...);
Note: Ensure that the passed in task is ObjectId type.
Credit to Yong Shun Yong for the help. Through trial and error, I solved the problem with the following code
Board.findOneAndUpdate(
{
_id: board,
"columns._id": column,
},
{
$push: {
"columns.$.tasks.$[].subtasks": req.body,
},
},
{
arrayFilters: [{ "task._id": task }],
}
)
I have a document containing an array of objects. I wanted to update a particular element in the array. Tried using MongoDB shell, it works fine. But when I use in Mongoose in NodeJs, it is not working. The command is same in both the cases.
NodeJs code
const updateAttendance = await classModel.updateOne(
{
_id: item.classId,
'studentAttendance.studentId': item.studentId,
},
{ $set: { 'studentAtendance.$.present': true } }
)
Schema defination
const mongoose = require('mongoose')
const moment = require('moment')
const student = mongoose.Schema({
studentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
unique: true,
},
present: {
type: Boolean,
default: false,
},
})
const classes = mongoose.Schema({
date: {
type: String,
required: true,
default: moment().format('DD/MM/YYYY'),
validate: {
validator: (value) => {
return moment(value, 'DD/MM/YYYY', true).isValid()
},
message: 'Provide a valid date in the format of DD/MM/YYYY',
},
},
courseId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Course',
},
studentAttendance: [
{
type: student,
},
],
})
module.exports = mongoose.model('Class', classes)
Sample data
{
"date": "20/06/2021",
"_id": "60cf5446970dc063e40356d3",
"courseId": "60ce2c3aca275c868089ac48",
"studentAttendance": [
{
"present": false,
"_id": "60cf5446970dc063e40356d4",
"studentId": "60ce315f9f83a24544414705"
},
{
"present": false,
"_id": "60cf5446970dc063e40356d5",
"studentId": "60ce31ba9f83a2454441470a"
},
{
"present": false,
"_id": "60cf5446970dc063e40356d6",
"studentId": "60ce38e49f83a24544414712"
}
],
"__v": 0
}
What am I doing wrong or where is the problem?
Without looking at the schema def, just taking a punt in the dark that you dont explicitly say its an ObjectId.
Easy solve, just wrap "item.studentId" in mongoose.Types.ObjectId().
So your new code would be like
const updateAttendance = await classModel.updateOne({
_id: mongoose.Types.ObjectId(item.classId),
'studentAttendance.studentId': mongoose.Types.ObjectId(item.studentId),
},
{ $set: { 'studentAtendance.$.present': true } }
)
Don't forget const mongoose = require('mongoose');
Based on the update your update statement needs 'updating'. try fixing the spelling of studentAttendance vs studentAtendance in the $set statement.
I have a collection like below, which has expire-time set like below as part of schema .
db.createCollection(
"userDetails",
{
capped: false,
validator: {
$jsonSchema: {
bsonType: "object",
required: ["userId","userName"],
properties: {
userId: {
bsonType: "string",
description: "must be a string and is required"
},
userName: {
bsonType: "string",
description: "must be a string and match the regular expression pattern"
},
}
}
},
validationLevel: "strict",
validationAction: "error"
}
);
db.userDetails.createIndex( { "userName": 1 }, { expireAfterSeconds:6000});
So now whenever it expires it is getting delete from the mongodb, but I have some other requirement where I have to notify some other service about this deletion so I tried below code but this will I have execute every time, also I am not getting any records.
template.execute("userDetails", new CollectionCallbackBoolean>() {
public Boolean doInCollection(userDetails.class, DBCollection collection) throws MongoException, DataAccessException {
List<Document> indexes = collection.getIndexInfo();
for (Document document : indexes) {
log.info("Docouments " + document.get("userName"))
}
}
return false;
}
});
So how to register to mongo for a callback to get these expired records using mongotemplate..
How would one approach doing this (https://docs.mongodb.com/v3.2/core/document-validation/):
db.createCollection( "contacts",
{ validator: { $or:
[
{ phone: { $type: "string" } },
{ email: { $regex: /#mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
]
}
} )
In this:
// database.js
import { Mongo } from 'meteor/mongo';
export const Test = new Mongo.Collection('Test');
Thanks
you first need to define your schema in meteor.
Lists.schema = new SimpleSchema({
name: {type: String},
incompleteCount: {type: Number, defaultValue: 0},
userId: {type: String, regEx: SimpleSchema.RegEx.Id, optional: true}
});
This example defines a schema with a few simple rules:
We specify that the name field of a list is required and must be a
string.
We specify the incompleteCount is a number, which on insertion is
set to 0 if not otherwise specified.
We specify that the userId, which is optional, must be a string that
looks like the ID of a user document.
It’s pretty straightforward to validate a document with a schema. We can write:
const list = {
name: 'My list',
incompleteCount: 3
};
Lists.schema.validate(list);
In this case, as the list is valid according to the schema, the validate() line will run without problems. If however, we wrote:
const list = {
name: 'My list',
incompleteCount: 3,
madeUpField: 'this should not be here'
};
Lists.schema.validate(list);
Then the validate() call will throw a ValidationError which contains details about what is wrong with the list document.
How can i avoid the insertion in mongoDB if there is no data. Because every time i use insert command it is creating _id without data.
Example : db.collection_name.insert({})
is creating _id in document. How to avoid it.
You can use mongoose ORM and can define validators like:
var UserSchema = new Schema({
name: { type: String, required: true }
});
Which will generate an error message that looks like:
name:
{ message: 'Validator "required" failed for path name',
name: 'ValidatorError',
path: 'name',
type: 'required' } }
MongoDB 3.2 has schema validation integrated.
So you can just check if "name" property exists, if not then the validation fail and then the Document will be not inserted at all.
https://docs.mongodb.com/v3.2/core/document-validation/
db.createCollection( "contacts",
{ validator: { $or:
[
{ phone: { $type: "string" } },
{ email: { $regex: /#mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
]
}
} )