ValidatorError: Cannot read property 'options' of undefined on undefined field - mongodb

I have Shape and ShapeOrientation models. A shape can have many shape orientations. So my models are as follows:
var shapeSchema = new mongoose.Schema({
name: { type: String },
mfrID: { type: String },
category: { type: mongoose.Schema.Types.ObjectId, ref: 'ShapeCategory' },
brand: { type: mongoose.Schema.Types.ObjectId, ref: 'ShapeBrand' },
available: { type: Boolean, default: false },
related: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Shape' }],
orientations: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ShapeOrientation' }],
owner: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
open: { type: Boolean, default: true },
thumb: { type: String },
thumbMime: { type: String },
thumbPath: { type: String },
shapeid: { type: String },
desc: { type: String },
verified: { type: Boolean, default: true }
My Shape Orientation Schema is thus:
var shapeOrientationSchema = new mongoose.Schema({
name: { type: String },
data: { type: String },
shape: { type: mongoose.Schema.Types.ObjectId, ref: 'Shape' },
shapeid: { type: String },
length: { type: Number },
width: { type: Number },
depth: { type: Number },
thumb: { type: String },
thumbMime: { type:String }
});
When I try to populate my shape orientations and shape at the same time for a massive import.
ShapeOrientation.insertMany(orientations)
.then(function(manyDocs){
console.log('hooked up and saved orientations.');
async.eachSeries(manyDocs, function(orientDoc, orientDone) {
Shape.findOne({shapeid: orientDoc.shapeid})
.then(function(foundShape){
foundShape.orientations.push(orientDoc._id);
foundShape.save(function(err) {
if(err) {
console.log('shape', foundShape)
console.log('cannot save shape', err)
orientDone();
return;
} else {
orientDone();
}
console.log('saved shape')
})
})
})
I get the following error on an undefined field of mongo.
cannot save shape { [ValidationError: Shape validation failed]
message: 'Shape validation failed',
name: 'ValidationError',
errors:
{ undefined:
{ [ValidatorError: Cannot read property 'options' of undefined]
properties: [Object],
message: 'Cannot read property \'options\' of undefined',
name: 'ValidatorError',
kind: 'cast',
path: undefined,
value: undefined } } }
I don't seem to have any required fields and I am just trying to save the related data while I populate the orientation.
Both _.id's of the Shape and the Orientation exist so I don't understand why it won't save.

Related

How to make an auto-increment field but it's in an object and inside an array by mongoose-sequence

I can only increment the name field outside, and the number field inside the image field and inside an object. This is really hard for me. Thanks if someone can help me.
const Chapter = new mongoose.Schema({
name: { type: Number },
book: { type: mongoose.Schema.Types.ObjectId, ref: 'books', required: true },
image: [
{
number: { type: Number },
url: { type: String, default: "" },
id: { type: String, default: "" }
}
],
createAt: { type: Date, default: Date.now },
deleteAt: { type: Date, default: Date.now },
updateAt: { type: Date, default: Date.now, commit: String },
});
Chapter.plugin(AutoIncrement, { inc_field: 'name' });
// Chapter.plugin(AutoIncrement, { inc_field: 'image.number' });
module.exports = Chapter;

Associate one schema with another

I have my user schema:
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
active: { type: Boolean, default: false }
});
I want to create a leave status schema. Data will be given by only one user about all leave status. I want to associate each one of the leave status to there respective user schema id. I tried leave status schema as the following:
const leaveSchema = new Schema({
leave: [
{
email: { type: String, required: true },
month: { type: String, required: true },
year: { type: Number, required: true },
earnedleave: { type: Number },
sickleave: { type: Number },
festivalleave: { type: Number },
compoff: { type: Number }
}
]
});
How can i associate my emailid with userschema. Can it be possible? If so, how can i tweak it?
We don't need to associate the schema to get leave based on user, You can use aggregation for that,
db.user.aggregate([
...
{$lookup: {from: "leave", localField: "email", foreignField: "leave.email", as: "leaves"}},
...
]);
Still, If you like to associate two collection, You have to use ref using ObjectId
const leaveSchema = new Schema({
leave: [
{
user: { type: Schema.Types.ObjectId, ref: 'user' }, //Your model name as reference
email: { type: String, required: true },
month: { type: String, required: true },
year: { type: Number, required: true },
earnedleave: { type: Number },
sickleave: { type: Number },
festivalleave: { type: Number },
compoff: { type: Number }
}
]
});

how to search for any value in the document

I want to search for all value present without specifying key explicitly. Is it possible with this type of schema? If so, how can I write my query. I tried to write query with other refs but I am unable to write without specifying key for each.
const pschema = new Schema({
user: {
type: Schema.Types.ObjectId, // combine by id
ref: "users" //existing model reference
},
company: {
empNo: {
type: Number,
required: true
},
status: {
type: String,
required: true
},...
},
personal: {
gender: {
type: String
},
dob: {
type: Date
},...
},
skills: {
type: [String],
required: true
},
experience: [
{
title: {
type: String,
required: true
},
company: {
type: String,
required: true
},
location: {
type: String
}...
}
],
education: [
{
school: {
type: String,
required: true
},
degree: {
type: String,
required: true
},
specialization: {
type: String
},..
}
],
social: {
twitter: {
type: String
},
facebook: {
type: String
},
linkedin: {
type: String
},...
}
});
For example: If i give linkedin url if should search in social-linkedin and same if i give c it should search in skills array

Reference 2 collection in 1 field

Is it possible to have more than 1 reference in a field. If not, is there anyway good way to make it?
I tried this one: (2 reference in productStaff)
var productSchema = mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
index: true
},
productNumber: {
type: Number,
required: true
},
client_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Client',
required: true
},
receiveDate: {
type: Date,
required: true
},
paymentDate: {
type : Date
},
deadline: {
type: Date,
required: true
},
remark: {
type: String,
default: null
},
productStaff: [{
staff: {
type : mongoose.Schema.Types.ObjectId,
ref: 'Staff'
},
assignment: {
type : mongoose.Schema.Types.ObjectId,
ref: 'Assignment'
}
}],
productItem: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'ProductItem',
default: null
}],
registrationDate: {
type: Date,
default: Date.now
}
});
But i got this error when adding the data:
Error: "Product validation failed: productStaff: Cast to Array failed for value \"[ { staff: '594b63b184e6290c386baa3f',\n assignment: '594b63b184e6290c386baa3f' },\n { staff: '594b63b184e6290c386baa3g',\n assignment: '594b63b184e6290c386baa3g' } ]\" at path \"productStaff\""
I'm made it this way because I need to save the staff who will do the product with their corresponding assignments.
Thanks a lot.

Ordering two reference arrays together

Suppose I have the following schemas:
var QuizSchema = new mongoose.Schema({
name: { type: String, required: true },
questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }],
questionGroups: [{ type: mongoose.Schema.Types.ObjectId, ref: 'QuestionGroup' }]
});
var QuestionSchema = new mongoose.Schema({
number: { type: String, required: true }, // e.g. 1, a, i, anything
question: { type: String, required: true },
type: { type: String, enum: ['multiple choice', 'multiple select', 'short answer'] },
choices: [String],
answers: [String]
});
var QuestionGroupSchema = new mongoose.Schema({
number: { type: String, required: true }, // e.g. 1, a, i, anything
prompt: { type: String },
questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }]
});
I am trying to design a way that will allow me to order questions and question groups together.
I was thinking maybe of adding a new field order
var QuizSchema = new mongoose.Schema({
// ...
order: [
{
type: { type: String, enum: ['Question', 'QuestionGroup'] },
id: mongoose.Schema.Types.ObjectId // reference
}
]
});
such that in the database, the field would contain something such as
[
{ type: 'Question', id: ObjectId('57867a34567g67790') },
{ type: 'Question', id: ObjectId('57867a34567g67765') },
{ type: 'QuestionGroup', id: ObjectId('69864b64765y45645') },
{ type: 'Question', id: ObjectId('57867a34567g67770') },
{ type: 'QuestionGroup', id: ObjectId('69864b64767y45647') }
]
This may mean that I would need to "populate" the ordered list of questions and question groups as
quiz.populate('questions questionGroups').exec(function (err, quiz) {
// sort questions and groups by the order
quiz.order = quiz.order.map(function (o) {
if (o.type === 'QuestionGroup') {
return quiz.questionGroups.id(o.id);
}
return quiz.questions.id(o.id);
});
});
So my question: is there a better way to design this?
Virtuals can come in handy here; without persisting order field in db and doing calculations on client each time:
var QuizSchema = new mongoose.Schema({
name: { type: String, required: true },
questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }],
questionGroups: [{ type: mongoose.Schema.Types.ObjectId, ref: 'QuestionGroup' }]
},
{
toObject: {
virtuals: true
},
toJSON: {
virtuals: true
}
}
);
QuizSchema
.virtual('order')
.get(function() {
return this.questions.concat(this.questionGroups); //questions followed by questionGroups
});
Sort on createdAt is of course optional, but for that you need to have this field in Question and QuestionGroup:
Quiz.find({}, function (err, quiz) {
//...
})
.populate({path : 'questions', options: {sort: { 'createdAt': 1 }}})
.populate({path : 'questionGroups', options: {sort: { 'createdAt': 1 }}});