I have create schema in mongoose
let userSchema = new Schema({
name: {
type: String,
required: true,
lowercase: true,
trim: true,
minLength: 4,
maxLength: 15
}
});
when I update it with this query
user.updateOne(
{ "_id" : body.id },
{ $set: {
name:body.name,
phone:body.phone,
designation:body.designation,
address:body.address
} }
).then(function (updateDate) {
var data={message:"success",data:updateDate}
callback(data)
}).catch(function (err) {
var data={message:"error",data:err}
callback(data);
});
It does not throw any error if I update string with 2 length.
There are few solutions on stackoverflow but these are not working in my case
Firstly, in your schema minLength must be minlength, and maxLength must be maxlength with lowercase l.
So your schema must be like this:
let userSchema = new Schema({
name: {
type: String,
required: true,
lowercase: true,
trim: true,
minlength: 4,
maxlength: 15
}
});
Secondly, you need to add {runValidators: true} option to updateOne.
Update validators are off by default - you need to specify the
runValidators option.
So your code must be like this:
user.updateOne(
{ _id: body.id },
{
$set: {
name: body.name,
phone: body.phone,
designation: body.designation,
address: body.address
}
},
{ runValidators: true }
)
.then(function(updateDate) {
var data = { message: "success", data: updateDate };
callback(data);
})
.catch(function(err) {
var data = { message: "error", data: err };
callback(data);
});
You simple open mongodb Compass and then go to Validation option and change validation level to strict mode.
Related
here is my code and I can add tour on my database but cannot retrieve them and return empty arrray
any method that return certain document from my database it return empty array but if used same model to add document its added
the model is
const mongoose = require("mongoose");
const tourschema = new mongoose.Schema(
{
name: {
type: String,
required: true,
unique: [true, "the Name must br unique"],
trim: true,
maxLength: [40, "name of tour must be less than 40 character"],
minLength: [10, "name of tour must be more than 10"],
},
rating: { type: Number, default: 10 },
price: {
type: Number,
required: false,
},
duration: {
type: Number,
required: true,
},
maxGroupSize: {
type: Number,
required: true,
},
difficulty: {
type: String,
required: true,
enum: {
values: ["easy", "medium", "difficult"],
message: "Difficulty must be easy or medium or difficult",
},
},
ratingavg: {
type: Number,
default: 4.5,
min: [1, "Rating must be above 1,0"],
max: [5, "Rating must be below 5,0"],
},
ratingquantity: {
type: Number,
default: 0,
},
pricediscount: {
type: Number,
validate: {
validator: function () {
//this only point to current document
return this.pricediscount < this.price;
},
message: "Discount price must be less than price",
},
},
summary: {
type: String,
trim: true,
},
description: {
type: String,
trim: true,
required: true,
},
imageCover: {
type: String,
required: true,
},
images: [String],
createdAt: {
type: Date,
default: Date.now(),
},
startdates: [Date],
screttour: {
type: Boolean,
default: false,
},
},
//second object passed is schema option
{
//each time data is outputed as json
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
//virtual means they ar not persist on database
tourschema.virtual("duration_in_weeks").get(function () {
return this.duration / 7;
});
tourschema.pre(/^find/, function (next) {
//this refer to query so we can chain
this.find({ screttour: { $ne: false } });
this.start = Date.now();
next();
});
tourschema.post(/^find/, function (doc, next) {
//this refer to query so we can chain
console.log(`Query took ${Date.now() - this.start} milliseconds!`);
next();
});
//aggregation middlewar
tourschema.pre("aggregate", function (next) {
//this refer to aggreagte pipeline
this.pipeline().unshift({ $match: { secrettour: { $ne: true } } });
next();
});
const tour = mongoose.model("newtour", tourschema);
module.exports = tour;
//another file calling the function
const tour = require("../models/tourmodel");
exports.get_tour_by_id = async (req, res) => {
try {
const founded_tour = await tour.find({});
res.status(200).json({
status: "success retrieve",
dataretrieved: founded_tour,
});
} catch (err) {
res.status(404).json({
status: "failed to retrieve",
});
}
};
I tried to rename my collection name because of mongoose is adding s to collection name from it self I expect to return document , this was work earlier but now it is not working can any one help?
I have to schema built with mongoose. This is the first schema.
const mongoose = require('mongoose');
const {
formatToCamelCase,
formatToCapitalizeEach
} = require('../src/util/formatter');
const formAttributeElementSchema = new mongoose.Schema({
elementTitle: {
type: String,
required: [true, 'Please provide element title in formAttributeSchema.'],
set: elementTitle => formatToCapitalizeEach(elementTitle),
},
datatype: {
type: String,
required: [true, 'Please provide data type for form attribute.'],
lowercase: true,
enum: {
values: ['string', 'number'],
message: 'We still not support {VALUE} data type in form attribute'
},
default: 'string',
},
attributeName: {
type: String,
required: [true, 'Please provide attribute name in form atribute schema.'],
set: attributeName => formatToCamelCase(attributeName),
},
isRequired: {
type: Boolean,
required: true,
default: true,
},
HTMLInputType: {
type: String,
required: [true, 'Please determine HTML input type for this form attribute.'],
enum: {
values: ['text', 'radio', 'checkbox'],
message: '{VALUE} is not supported yet. Please use supported type.',
},
},
maxLength: {
type: Number,
required: false,
validate: {
validator: (maxLength) => {
if (maxLength <= 0) return false;
},
message: 'Max length value can not have 0 or negative value.',
}
},
minLength: {
type: Number,
required: false,
validate: {
validator: (minLength) => {
if (minLength < 0) return false;
},
message: 'Min length can not have negative value.'
}
}
}, { _id: false });
const FormAttributeElement = mongoose.model('FormAttributeElement', formAttributeElementSchema);
module.exports = { FormAttributeElement };
and the second schema is:
const mongoose = require('mongoose');
const { formatToCapitalizeEach } = require('../src/util/formatter');
const { emailValidator } = require('../src/util/validator');
const { FormAttributeElement } = require('./formAttributeElement');
const dynamicFormDetails = new mongoose.Schema({
formTitle: {
type: String,
required: [true, 'Please provide form title.'],
set: formTitle => formatToCapitalizeEach(formTitle),
},
issuer: {
type: String,
required: [true, 'Please provide issuer email on form detail.'],
lowercase: true,
validate: {
validator: (issuer) => emailValidator(issuer),
message: 'Please makse sure use correct email format in issuer field on form detail attribute.',
},
},
startAt: {
type: Date,
required: [true, 'please provide date on startAt attribute.'],
},
closedAt: {
type: Date,
required: [true, 'Please provide date on closedAt attribute']
},
formShape: {
type: Array,
required: [true, 'Please provide form shape in form details.'],
validate: {
validator: (formShape) => {
for (let i = 0; i < formShape.length; i += 1) {
if (!formShape[i] instanceof FormAttributeElement) return false;
}
},
message: 'Form body only can be instance of FormAttributeElement',
},
},
});
const DynamicFormDetail = mongoose.model('DynamicFormDetail', dynamicFormDetails);
module.exports = { DynamicFormDetail };
now, i want to test my schema, especially it's validation using this code:
const { mongodbAtlasConnection } = require('../db/mongodb-connection');
const { DynamicFormDetail } = require('./dynamicForm');
const { FormAttributeElement } = require('./formAttributeElement');
const main = async () => {
let formElements = [];
let element;
const body = [
{
elementTitle: 'test aku hanya ngetes',
datatype: 'anjir harusnya gabisa sih',
isRequired: true,
HTMLInputType: 'blah',
}
]
body.forEach((data) => {
element = new FormAttributeElement({
elementTitle: data.elementTitle,
datatype: data.datatype,
attributeName: data.elementTitle,
isRequired: data.isRequired,
HTMLInputType: data.HTMLInputType,
});
formElements.push(element);
});
const formDetails = new DynamicFormDetail({
formTitle: 'test 123 form title',
issuer: 'lucky#gmail.com',
startAt: '2021-10-6',
closedAt: '2021-10-7',
formShape: formElements,
});
try {
await mongodbAtlasConnection();
const result = await formDetails.save();
console.log(result);
} catch (e) {
console.log(e)
}
}
main();
Yes, in DynamicFormDetail model, the validation is work just fine. If i wasn't supplied required attribute it throws an error. But, the problem is in the instantization of FormAttributeElement (inside of forEach loop) i can insert anything even if it's againts the constraint i defined in the schema. How to trigger that validation if i don't want to use .save() function on that model?
I have review and product model.If user give review on specific product(id) then it is stored in review model database but i donot like to store user review in product model database .so, i used virtual populate in product model instead of child referencing.After using virtual properties,if we use product id to see details,we can see review of user in json format but not saved in database.But the problem is my virtual properties (In Product Model) not working as it doesnt show review of user in json format when i send the request in that product id which already have review by user(stored in review model database).what is the problem here?
User Review on Product (id) stored in database
Sending Request of that product id to see review of user in json format using virtual properties(but no review found in json)
In Product Model
const productSchema = new Schema({
name: {
type: String,
required: true,
trim: true,
},
slug: {
type: String,
required: true,
unique: true,
},
price: {
type: String,
required: true,
},
quantity: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
trim: true,
},
offer: {
type: Number,
},
discount: {
type: Number,
},
productPictures: [{
img: {
type: String,
},
}, ],
mainCategory: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
sub1Category: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
sub2Category: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "admin",
required: true,
},
vendor: {
type: mongoose.Schema.Types.ObjectId,
ref: "vendor",
},
createdAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
updatedAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
},
{
toJson: { virtuals: true },
toObject: { virtuals: true },
}
);
productSchema.virtual("reviews", {
ref: "review",
foreignField: "product",
localField: "_id",
// justOne: true
});
const Product = mongoose.model("product", productSchema);
module.exports = Product;
In Review Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const moment = require("moment");
const reviewSchema = new Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: [true, "Review must belong to user"],
},
product: {
type: mongoose.Schema.Types.ObjectId,
ref: "product",
required: [true, "Review must belong to the product"],
},
review: {
type: String,
required: [true, "Review cannot be empty"],
},
rating: {
type: Number,
min: 1,
max: 5,
},
createdAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
updateddAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
}, {
toJson: { virtuals: true },
toObject: { virtuals: true },
});
// pre middleware and populating user and product(we can also do populate in getAllReview in controller)
reviewSchema.pre(/^find/, function(next) {
// ^find here is we use regex and can able to find,findOne ...etc
this.populate({
path: "product",
select: " _id name",
}).populate({
path: "user",
select: " _id fullName",
});
next()
});
const Review = mongoose.model("review", reviewSchema);
module.exports = Review;
In Review.js
const Review = require("../../models/Review.Models")
exports.createReview = async(req, res) => {
const review = await Review.create(req.body)
return res.status(201).json({
status: true,
review
})
}
exports.getAllReviews = async(req, res) => {
try {
const reviews = await Review.find()
return res.status(200).json({
status: true,
totalReviews: reviews.length,
reviews
})
} catch (error) {
return res.status(400).json({
status: false,
error
})
}}
In Product.js
const Product = require("../../models/Product.Models");
exports.getProductDetailsById = async(req, res) => {
try {
const { productId } = req.params;
// const { productId } = req.body;
if (productId) {
const products = await Product.findOne({ _id: productId })
.populate('reviews')
return res.status(200).json({
status: true,
products,
});
} else {
console.log("error display");
return res.status(400).json({
status: false,
error: "params required...",
});
}
} catch (error) {
return res.status(400).json({
status: false,
error: error,
});
}
try this in Product.js
try {
if (productId) {
const products = await Product.findOne({ _id: productId }).populate(
"reviews"
);
console.log(products);
if (products) {
return res.status(200).json({
status: true,
message: "Products is listed",
products,
reviw: products.reviews,
});
only need to add on response sending
return res.status(200).json({
status: true,
message: "Products is listed",
products,
reviw: products.reviews,
});
I have the following schema:
const postsStatsSchema = new Schema({
postid: {
type: String,
maxlength: [128, "post ID must be at most 128"],
required: true
},
likecounter: {
type: Number,
default: 0,
min: 0,
required: true
}
});
const userStatsSchema = new Schema({
username: {
type: String,
required: true,
maxlength: [50, "Name length must be at most 50"]
},
posts: {
type: [postsStatsSchema],
required: true
}
});
const statisticsSchema = new Schema({
month: {
type: Number,
required: true
},
users: {
type: [userStatsSchema],
required: true
}
}, {
timestamps: true
});
I'm trying to increment (or create, if the document does not exist) the 'likecounter' in the postsStats object. I tried many different ways, but non were successful. This is the last thing I tried:
let update = {};
update['$inc'] = {};
update['$inc'] = {'users.$.username.user.$.posts.somepost.likecounter': 1000};
try {
const res = await stats.findOneAndUpdate({month: 100}, update, {'upsert': true});
console.log(res);
} catch (err) {
console.log(err);
}
The error I'm getting on the code above is:
MongoError: Too many positional (i.e. '$') elements found in path
I tried many variations, with and without the '$' sign, but only managed to increment the month. I believe it is something with the nested document that Im doing wrong but just can't figure out what it is.
I am trying to modify keyStone.js project to match my requirements,i am having problems adding a new user from the server side
var User = keystone.list('User');
User.add({
name: {first:"Abcd",
last:"xyz" },
email: "abc#xyz.com",
password: "password",
isAdmin: true
});
User.register();
But this isn't creating a new user in the MongoDB, any ideas what i maybe doing wrong?
You are mixing up schema definition for User and creation of a User
This could be your schema definition in models/User.js:
var User = keystone.list('User');
User.add({
name: { type: Types.Name, required: true, initial: true },
email: { type: Types.Email, required: true, initial: true },
password: { type: Types.Password, required: true, initial: true },
isAdmin: { type: Boolean },
});
User.register();
Then you can create a user like this:
var User = keystone.list('User').model;
var user = new User({
name: { first:'Abcd', last:'xyz' },
email: 'abc#xyz.com',
password: 'password',
isAdmin: true
});
user.save(function (err) {
if (err) {
// handle error
return console.log(err);
}
// user has been saved
console.log(user);
});