Mongoose - Validate ObjectID related document - mongodb

I need to validate as required a field "product" in Model Event. Product is ObjectID reference to Product Model.
I tried with this 2 approaches, but it is not validating
product: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Product',
required: true
}]
},
product: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Product',
required: function () {
return this.product.length > 0
},
}]
},
The Event is being created anyway, and when I add no products, field product is an empty array.
Any idea how can I validate it?
Models:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Product = require('../models/Product');
const moment = require('moment');
const EventSchema = new Schema({
client: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Client'
}]
},
product: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Product',
required: true
}]
},
date: {
type: Date,
maxlength: 64,
lowercase: true,
trim: true
},
place: {
type: String,
maxlength: 1200,
minlength: 1,
},
price: {
type: Number
},
comment: {
type: String,
maxlength: 12000,
minlength: 1,
},
status: {
type: Number,
min: 0,
max: 1,
default: 0,
validate: {
validator: Number.isInteger,
message: '{VALUE} is not an integer value'
}
},
},
{
toObject: { virtuals: true },
toJSON: { virtuals: true }
},
{
timestamps: true
},
);
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Provider = require('./Provider')
const ProductSchema = new Schema({
name: {
type: String,
maxlength: 64,
minlength: 1,
required: [true, 'Product name is required'],
},
brand: {
type: String,
maxlength: 64,
minlength: 1,
},
description: {
type: String,
maxlength: 12000,
min: 1,
},
comment: {
type: String,
maxlength: 12000,
minlength: 1
},
state: {
type: String,
maxlength: 64,
minlength: 0
},
disponible: {
type: Boolean,
default: true
},
price: {
type: Number,
default: 0,
min: 0,
max: 999999
},
provider: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Provider'
}]
},
category: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Category'
}]
},
event: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Event'
}]
},
image: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Image'
}]
},
},
{
toObject: { virtuals: true },
toJSON: { virtuals: true }
},
{
timestamps: true
});

You can use custom validators feature of mongoose.
If the validator function returns undefined or a truthy value, validation succeeds. If it returns falsy (except undefined) or throws an error, validation fails.
product: {
type: [
{
type: Schema.Types.ObjectId,
ref: "Product",
required: true
}
],
validate: {
validator: function(v) {
return v !== null && v.length > 0;
},
message: props => "product is null or empty"
}
}
Now when you don't send product field, or send it empty array it will give validation error.

const notEmpty = function(users){
if(users.length === 0){return false}
else { return true }
}
const EventSchema = new Schema({
product: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Product',
required: true,
validate: [notEmpty, 'Please add at least one']
}]
}
})

Related

How to generate auto increment count field using Mongodb Schema

I have a database related to the interview process which consists of multiple fields.
basically, there are 5 APIs
POST - (Candidate info) - for entering candidate data
PATCH - for updating candidate info
PATCH - (for Short Listing and reviewing) - updates in existing candidate
PATCH - (for Scheduling the candidate interview) - entering the interview field which is an array object.
GET Method
I want auto increment for the count field under Interview Round Count
whenever the PATCH Method is updated for the same candidate (data updated successfully)
How can I do that in Mongodb
Complete Schema:
const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const { Schema } = mongoose;
const { EMAIL } = require('../../config/patterns.js');
const InterviewSchema = new Schema(
{
firstName: {
type: String,
required: true,
trim: true,
maxlength: 30,
},
lastName: {
type: String,
trim: true,
maxlength: 30,
},
email: {
type: String,
required: true,
trim: true,
match: EMAIL,
},
gender: {
type: String,
required: true,
enum: ['male', 'female', 'other'],
},
contactNumber: {
type: Number,
unique: true,
required: true,
},
alternateContactNumber: {
type: Number,
},
resume: {
type: String,
required: true,
},
designation: {
type: String,
required: true,
enum: ['trainee', 'se', 'sse', 'tl', 'systemEngineer'],
},
profile: {
type: String,
required: true,
enum: [
'react',
'reactNative',
'node',
'fullstack',
'php',
'ios',
'android',
'python',
],
},
experience: {
years: {
type: Number,
required: true,
},
months: {
type: Number,
required: true,
},
},
ctc: {
current: {
type: Number,
required: [true, 'In LPA'],
},
expected: {
type: Number,
required: [true, 'In LPA'],
},
offered: {
type: Number,
required: [true, 'In LPA'],
},
},
noticePeriod: {
type: Number,
default: 0,
},
referrer: {
type: {
type: String,
enum: ['consultant', 'employee', 'website', 'social'],
},
name: {
type: String,
trim: true,
required: true,
},
},
status: {
type: String,
enum: [
'shortlisting',
'shortlisted',
'interviewing',
'selected',
'rejected',
'onHold',
'denied',
'offerSent',
'joined',
'cancel',
],
},
// Shortling the Candidate - PATCH Method
reviewer: {
name: {
type: String,
trim: true,
required: true,
},
email: {
type: String,
trim: true,
required: true,
},
id: {
type: Number,
required: true,
},
},
date: {
type: Date,
default: Date.now,
},
// Scheduling the interview (this can be repeated no.of times for the interview round)
// represented in Array object
interview: [
{
interviewerName: {
type: String,
trim: true,
},
date: {
type: Date,
default: Date.now,
},
mode: {
type: String,
enum: ['telephonic', 'video', 'f2f'],
default: 'telephonic',
},
meeting: {
link: {
type: String,
trim: true,
},
platform: {
type: String,
trim: true,
},
},
round: {
count: { // want auto-increment count
type: Number,
},
type: {
type: String,
enum: ['written', 'technical', 'hr'],
},
},
interviewStatus: {
type: String,
enum: ['rejected', 'onHold', 'selected', 'schedule'],
},
feedback: {
technical: {
type: Number,
required: true,
min: 1,
max: 5,
},
logical: {
type: Number,
required: true,
min: 1,
max: 5,
},
communication: {
type: Number,
required: true,
min: 1,
max: 5,
},
comment: {
type: String,
min: 10,
max: 200,
},
},
recommendation: {
type: String,
enum: ['yes', 'no'],
},
},
],
},
{
timestamps: true,
},
);
InterviewSchema.plugin(mongoosePaginate);
const InterviewProcess = mongoose.model('interviewprocess', InterviewSchema);
module.exports = InterviewProcess;

Is it possible to have two types of objects in an array of mongoose schema

I am building an e-commerce application and this is my orders schema.
const mongoose = require("mongoose");
const orderSchema = new mongoose.Schema({
buyer: {
type: mongoose.Schema.Types.ObjectId,
ref: "buyer",
required: true
},
items: [{
item: {
type: mongoose.Schema.Types.ObjectId,
ref: "item",
},
quantity: {
type: Number,
default: 1
}}
],
seller: {
type: mongoose.Schema.Types.ObjectId,
ref: "seller",
required: true
},
location: {
type: {
type: "String",
enum:['Point']
},
coordinates: {
type: [Number],
index: '2dsphere'
}
},
sendAt:{
type: Date,
default: Date.now
}
});
const orderModel = mongoose.model("orders", orderSchema);
module.exports = orderModel;
I want to have an array having item-reference-id and quantity.
But with the above schema when i enter data, each item is acting as an another sub-document and having _id. Query response image.
I have found solution:
order: [
{
_id: false,
item: {
type: mongoose.Schema.Types.ObjectId,
ref: "items",
required: true,
},
quantity: { type: Number },
},
],
_id: false will stop the subdocument from creating another id for the subdocument.

How to store range(in geocircle radius form) in mongoose schema

I am building an e-commerce application. Every store has a delivery range so i want to set delivery range of every store in the database to show the store only to those who falls in the delivery range.
Store Schema.
const mongoose = require("mongoose");
const sellerSchema = new mongoose.Schema({
name:{
type: String,
required: true,
},
type: {
type: String,
required: true
},
location: {
type: {
type: "String",
enum:['Point']
},
coordinates: {
type: [Number],
index: '2dsphere'
}
},
owner: {
type: String,
required: true
},
items: [{
type: mongoose.Schema.Types.ObjectId,
ref: "items"
}],
contact: {
type: String,
required: true
},
loginId: {
index:true,
unique: true,
type: String,
},
password: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
});
const sellerModel = mongoose.model("sellers",sellerSchema);
module.exports = sellerModel;

find one with multiple conditions mongoose mongodb

I am trying to obtain data from mongodb. This is the scenario. Each user has a following property(array) that takes an array of users id.
The user model is as below
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
followers: [{ type: mongoose.Types.ObjectId, ref: "user" }],
following: [{ type: mongoose.Types.ObjectId, ref: "user" }],
});
in simple terms. I need to use two conditions where postedBy: { $in: req.user.following }, or postedBy:req.user._id
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
photo: {
type: String,
required: true,
},
likes: [{ type: mongoose.Schema.ObjectId, ref: "user" }],
comments: [
{
text: String,
postedBy: { type: mongoose.Schema.Types.ObjectId, ref: "user" },
},
],
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
},
});
I have not figured out the second condition to add in the code below.
router.get("/getSubPost", requireLogin, async (req, res) => {
try {
const result = await Post.find({
postedBy: { $in: req.user.following },
})
.populate("postedBy", "-password")
.populate("comments.postedBy", "_id name");
res.json({ result });
} catch (error) {
console.log(error);
}
});

How to push an item to a nested array?

I am trying to make an api with express.js and mongoDB (using mongoose) and don't know how to properly add an item to my existing array (nextUp). For example I have an existing User in my database with templates: { issues: { nextUp: [], inProgress: [], completed: [] } } and want to add e.g. {issueName: 'MyName', issueDate: '20/5/2020'} to nextUp field.
const mongoose = require('mongoose');
const { Schema } = mongoose;
const UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
minlength: 3,
sparse: true,
},
email: {
type: String,
required: true,
unique: true,
minlength: 5,
maxlength: 255,
sparse: true,
},
password: {
type: String,
required: true,
minlength: 8,
sparse: true,
},
newsletterSubscribed: {
type: Boolean,
},
termsAndPolicyAgreement: {
type: Boolean,
required: true,
},
templates: {
title: {
type: String,
},
description: {
type: String,
},
issues: {
nextUp: [
{
issueName: {
type: String,
},
issueDate: {
type: String,
},
},
],
inProgress: [
{
issueName: {
type: String,
},
issueDate: {
type: String,
},
},
],
completed: [
{
issueName: {
type: String,
},
issueDate: {
type: String,
},
},
],
},
},
});
const UserModel = mongoose.model('user', UserSchema);
module.exports = UserModel;
I've tried to do that but my item hasn't added. (username Kacper exists there is no problem with that).
UserModel.findOneAndUpdate(
{ username: 'Kacper' },
{
$push: {
nextUp: [
{
issueName: 'MY NEW ISSUE',
issueDate: 'MY ISSUE DATE',
},
],
},
},
);