Reference 2 collection in 1 field - mongodb

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.

Related

How to make sure that only one of two fields are populated in mongoDB

I am using mongoose as an ODM and trying to model an animal/pet. In the model I have 2 fields, parent and shelter. I want to make sure that pet belongs to a person or a shelter but not both. What constraints would allow me to do this.
My model in JS:-
const petSchema = mongoose.Schema({
name: {
type: String,
required: [true, "Pet must have a name."],
trim: true
},
species: {
type: String,
required: [true, "Pet must have a species."]
},
parent: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
shelter: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Shelter'
}
}
I am new to databases and their jargons, correct me if any error in question.
Thank you.
You can use the required function to determine this as follows:
const petSchema = mongoose.Schema({
name: {
type: String,
required: [true, "Pet must have a name."],
trim: true
},
species: {
type: String,
required: [true, "Pet must have a species."]
},
parent: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: function() {
return !this.shelter;
}
},
shelter: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Shelter',
required: function() {
return !this.parent;
}
}
}
I ended up using pre validate middleware in mongoose:-
petSchema.pre('validate', function (next) {
if((this.parent && this.shelter) || (!this.parent && !this.shelter))
return next(new Error("At least and Only one field(parent, shelter) should be populated"))
next()
})

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;

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

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 }}});