How to refer multiple schema in my mongoose schema? - node.js

I am creating a website where you can take and upload tests.
So there are two kinds of users Company(upload test) and Candidate(take test).
Now when i create a token how do I refer to both the schema's (schema of company and schema of candidate)?
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema.Types;
let tokenSchema = new mongoose.Schema({
userId: { type: ObjectId, ref: "<?>" }
});
module.exports = mongoose.model("Token", tokenSchema);

Let's sat this is how you export both candidate and company schema:
module.exports = mongoose.model("Candidate", candidateSchema)
module.exports = mongoose.model("Company", companySchema)
Your token schema should be like the following:
let tokenSchema = new mongoose.Schema(
candidateId: { type: ObjectId, ref: "Candidate" },
comoanyId:{ type: ObjectId, ref: "Company" },
);

Related

Can I set a element of my mongoose model to be strictly of some particular other models?

My subsection model should strictly be a type of lecture or quiz model only.
I want something like this. Any idea how to implement it properly?
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const subSectionSchema = new mongoose.Schema({
subSection:{
type:ObjectId,
enum:["Lecture","Quiz"]
}
});
module.exports = mongoose.model("SubSection", subSectionSchema);
Although I can always do this way...check which type it is and set that value.
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const subSectionSchema = new mongoose.Schema({
lecture: {
type: ObjectId,
ref: "Lecture",
},
quiz: {
type: ObjectId,
ref: "Quiz",
},
});
module.exports = mongoose.model("SubSection", subSectionSchema);
But I am looking for something simple.
I'm not sure if I understood your question, but I think what you're looking for are dynamic references. This feature allow us to have dynamic properties on our MongoDB collection.
You'll basically need two properties for it, one for the ObjectID, other for the reference. Whenever you need to populate the reference, it will automatically detects which entity/collection to use.
Here's a quick example from Mongoose docs:
const commentSchema = new Schema({
body: { type: String, required: true },
on: {
type: Schema.Types.ObjectId,
required: true,
// Instead of a hardcoded model name in `ref`, `refPath` means Mongoose
// will look at the `onModel` property to find the right model.
refPath: 'onModel'
},
onModel: {
type: String,
required: true,
enum: ['BlogPost', 'Product']
}
});
const Product = mongoose.model('Product', new Schema({ name: String }));
const BlogPost = mongoose.model('BlogPost', new Schema({ title: String }));
const Comment = mongoose.model('Comment', commentSchema);

How to perform inner join in mongoose

I was googling for last two days but no success. I need to perform inner join in mongoose with two schema but not getting response my other collection.
My question is what am I missing in my code? Please help me with this.
I want to get result of class and subjects also.
exports.classSubjectList = async (req, res, next) => {
const obj = await ClassSubject.find().populate('classmodel').exec();
res.status(200).json({
success: true,
response: obj
});
};
//ClassSubjectModel
const mongoose = require('mongoose');
mongoose.Promise = global.Promise
const Schema = mongoose.Schema
const classModel = require('../class/classModel');
const subjectModel = require('../subject/subjectModel');
var classsubject = new Schema({
ClassId: String,
SubjectId : String,
IsShow: { type: Boolean, default : true},
classmodel: { type: mongoose.Schema.Types.ObjectId, ref: classModel },
subjectmodel: { type: mongoose.Schema.Types.ObjectId, ref: subjectModel },
});
//Class Model
const mongoose = require('mongoose');
mongoose.Promise = global.Promise
const Schema = mongoose.Schema
var classinfo = new Schema({
ClassName: String,
IsShow: { type: Boolean, default : true},
});
module.exports = mongoose.model('classinfo', classinfo);
//SUBJECT Model
const mongoose = require('mongoose');
mongoose.Promise = global.Promise
const Schema = mongoose.Schema
var subject = new Schema({
SubjectName: String,
IsShow: Boolean,
});
module.exports = mongoose.model('subject', subject);
result
[
{
"IsShow": true,
"_id": "5e1efc0f354849246c472cfe",
"SubjectId": "5e1da60bf52acb30b87e92c4",
"ClassId": "5e1ec13ed777bf28d01e2481",
"__v": 0
}]
You should define ref as the name of your schema & not the object reference
Do it like this
classmodel: { type: mongoose.Schema.Types.ObjectId, ref: 'classinfo' }
subjectmodel: { type: mongoose.Schema.Types.ObjectId, ref: 'subject' },
// here 'classinfo' & 'subject' are the names you defined your schema with
You should populate both if you want a proper inner join
const obj = await ClassSubject.find().populate('classmodel').populate('subject').exec();
You must store ids of class & reference in classmodel & subjectmodel
key of your document for this to work
Hope this helps

Cannot overwrite model once compiled

I want to insert records in mongodb using mongoose but i am getting error "cannot overwrite "story" model once compiled"
app.post('/getdata', (req, res, next) => {
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mydb');
var Schema = mongoose.Schema;
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
res.send("Om Success");
})
You are initializing mongoose and all the schema everytime someone hits /getdata post endpoint and as you have express app main process will not be terminated until you so that manually or any unhandled error occurs.
So currently in your program, this is the scenario:
First Request to /getdata
Your mongoose will be initialized and Story and Person models are registered with mongoose object and this is global so you can use it from anywhere and this is unique too(your error is here).
From second Request to /getdata
You already registered Story and Person models with mongodb://localhost:27017/mydb DB so as it needs unique model it will throw an error.
Solution
put your initialization code somewhere else where it will be called only once. You can consider structure something like this: https://github.com/ridhamtarpara/express-es8-rest-boilerplate/blob/master/src/api/services/user/user.model.js
or if you want to do this in the same file(not recommended for obvious reasons) do something like this
var express = require('express');
var mongoose = require('mongoose');
var app = express();
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost:27017/mydb');
var personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
app.post('/getdata', (req, res, next) =>
{
res.send("Om Success");
})

How to show relationship in mongoose?

I have two mongoose schemas 'user' and 'project' and i want to show relationship between these schemas like in mysql. How to do this?
And how can i pass user while creating a project?
User.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt-nodejs');
const Schema = mongoose.Schema();
const UserSchema = mongoose.Schema({
fullname: {type: String},
username : {type:String},
password: {type:String}
});
UserSchema.methods.encryptPassword = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(10), null);
};
UserSchema.methods.comparePassword = function(userPassword, cb) {
bcrypt.compare(userPassword, this.password, (err, isMatch) => {
if(err) throw err;
cb(null, isMatch);
});
}
module.exports = mongoose.model('User', UserSchema);
project.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema();
const User = require('./user');
const ProjectSchema = mongoose.Schema({
title: {type: String, required: true},
description: {type:String},
created_at: { type: Date, default: Date.now },
publish : { type: Boolean, default: false}
});
module.exports = mongoose.model('Project', ProjectSchema);
Creating schema in Mongoose isn't like creating schema in Relational DBMS, such as MySQL, PostGreSQL.
You can use objectId, bro.
If one project just can be handled by one user, you can use something like this.
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
But if one project is handled by multi users
users: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}]
Hope it will help
Schema Change
To create a relationship in Mongoose (MongoDB), create a property on your schema with the following properties
1. type: mongoose.Schema.Types.ObjectId
2. ref: "string name of the Collection this reference lives in"
For example, if you wanted a project to contain a reference to the users inside of it, you could do the fallowing
const mongoose = require('mongoose');
const Schema = mongoose.Schema();
const User = require('./user');
const ProjectSchema = mongoose.Schema({
title: {type: String, required: true},
description: {type:String},
created_at: { type: Date, default: Date.now },
publish : { type: Boolean, default: false},
users: [{type: Schema.Types.ObjectId, ref: 'User'}]
});
module.exports = mongoose.model('Project', ProjectSchema);
Example Opertaion
Given the above Schema, if you wanted to create a new Project and add users to it during creation, you would need to have those users' _id properties on hand (i.e. cached). That could mean making a prior query to the db to get all the users who will be a part of this project or having some client send you the user ids.
A much better option would be to create a project, and update its' users property as users are added or removed.
Here is a quick example
const Project = require('./models/Project.js');
let userIds = // get the user _ids some how
Project.create({
title: 'A sample',
description: 'The usual',
publish: true,
users: userIds
})
.then(callback);

mongoose - possible circular dependency?

I have the following mongoose models in my express app:
//dog.js
var mongoose = require("mongoose");
var dogSchema = (exports.dogSchema = mongoose.Schema({
name: { type: String, required: true },
}));
Then I import dog.js to my user.js
//user.js
var mongoose = require("mongoose");
var dog = require("./dog");
var userSchema = mongoose.Schema({
user: { type: String, required: true },
pass: { type: String, required: true },
dogs: [dog.dogSchema],
});
Now, from my routes I am creating a new user like this:
var user = require("../models/user");
var dog = require("../models/dog");
dog = new dog.Dog(dogData);
user = new user.User(data); //this will of course contain also dogData
user.save(next);
Is this the correct way to do this kind of operation? I have the feeling that I might be generating a circular dependency somehow, and anyway it does not look right to me. Any ideas on how to create sub-documents where the schema is from another model file?
You can create simultaneous references in two directions without creating circular problems. Create a reference from one document to the other using ref. From the docs:
http://mongoosejs.com/docs/populate.html
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
Then you can then choose to load the sub document using populate
Story.find({ --your criteria-- })
.populate('_creator')
.exec(function (err, story) {../});
You can then store the 2 schemas in separate .js files and require them both

Resources