How to get a list of available Mongoose Discriminators? - node.js

Given a situation where you have a User Scheme that you use to create a base model called User. And then for user roles, you use mongoose discriminators to create inherited models called Admin, Employee and Client. Is there a way to programmatically determine how many discriminations/inheritances/roles of the User model are available, as well as the available names?
My question in terms of code:
File: models/user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var options = {discriminatorKey: 'role'};
var userSchema = mongoose.Schema({
name: String,
email: String,
password: String,
},options);
var User = mongoose.model('User', userSchema);
var Client = User.discriminator("Client", mongoose.Schema({
Address : String,
Tax_identification : String,
Phone_number : String,
Internal_Remarks : String,
CRM_status : String,
Recent_contact : String,
}));
var Employee = User.discriminator("Employee",mongoose.Schema({
Staff_Id: String,
}));
module.exports = {User: User, Client: Client, Employee: Employee };
File: controllers/usersController.js
var User = require('../models/user.js').User;
module.exports = {
registerRoutes: function(app){
app.get('user/create',this.userCreateCallback)
},
userCreateCallback: function(req,res){
//Get Available User Roles - The function below doesn't exist,
//Just what I hypothetically want to achieve:
User.geAvailableDiscriminators(function(err,roles){
res.render('user/create',{roles:roles})
});
}
};
I hope I managed to express what I want to do. Alternative approaches are also welcome.

Since v4.11.13, mongoose model has model.discriminators which is an array of models, keyed on the name of the discriminator model.
In your case if you do console.log(User.discriminators) you will get:
{
Client: {
....
},
Employee: {
}
}
As far as I can see, this is not documented anywhere.
Line 158 in lib.helpers.model.discriminators.js is where this is created.

I think you want to fetch the names and values of all the discriminators as for the names you can simply use
User.discriminators
but for finding values you can use this
return Promise.all(Object.keys(discriminators).map(i =>
discriminators[i].find({ userId: this._id }))
).then(promiseResults =>
promiseResults.reduce((arr, el) => arr.concat(el), [])
);
you need to put userId under each discriminators for that.

Related

How insert one-to-one, one-to-many relationship using nodejs with mongoDB

I have two collections in my database those are following
student
course
I want to insert data's like one-to-one, one-to-many relationship.
example
Am sent following data's in my form-data
name
email
phone
password
course_name
course_cost
The above data's name, email, phone, password stored in student table.
And course_name, course_cost stored to course table with student_id.
This is my code:
route/students.js
const express = require('express');
const path = require('path');
const config = require('../config/database');
const router = express.Router();
let Student = require('../models/student_model');
router.post('/add_student', function(req, res){
let data = new Student();
data.name = req.body.name;
data.email = req.body.email;
data.phone = req.body.phone;
data.password = req.body.password;
data.save(function(err, data){
if(err) throw err;
res.send(data);
});
});
module.exports = router;
models/student_model.js
const mongoose = require('mongoose');
let StudentSchema = mongoose.Schema({
name:{
type: String
},
email:{
type: String
},
phone:{
type: String
},
password:{
type: String
},
}, { collection: 'student' });
const Student = module.exports = mongoose.model('Student', StudentSchema);
This is my API call:
My above code am done store student data stored in student table, but i don't know how to add one-to-one relationship
I think first you need to redesign the schema. Considering you have two different collections for student and course, you need a reference of course in student and student reference in course collection. This will help you to execute following kind of queries.
Get list of courses for student x.
Get a list of students who have enrolled for course ABC.
Add courses array in student schema and students array in courses schema.
Check this out.
In your route you request name, email, phone, password. Then you try insert course_name, course_cost. You need to insert student_id in course collection
This is an old question, however, i believe many people may be looking for a solution to this similar schema relation design. You need to declare a One to Many schema relation in your Model.
const StudentSchema = new Schema({
name: String,
email: String,
phone: String,
password: String,
course: [courseSchema] //this will be the relationship
})
const CourseSchema = new Schema({
course_name: String,
course_cost: String
})
const Student = mongoose.model('student', StudentSchema)
module.export = Student;

How to implement more than one collection in get() function?

My model university.js
const mongoose = require('mongoose');
const UniversitySchema = mongoose.Schema({
worldranking:String,
countryranking:String,
universityname:String,
bachelorprogram:String,
masterprogram:String,
phdprogram:String,
country:String
},{collection:'us'});
const University =module.exports = mongoose.model('University',UniversitySchema);
My route.js
const express = require('express');
const router = express.Router();
const University = require('../models/university');
//retrieving data
//router.get('/universities',(req,res,next)=>{
// University.find(function(err,universities){
// if(err)
// {
// res.json(err);
//}
// res.json(universities);
//});
//});
router.get('/usa',function(req,res,next){
University.find()
.then(function(doc){
res.json({universities:doc});
});
});
module.exports= router;
How to implement multiple collections in this get() function? I put my collection name in the model. Please help me with a solution to call multiple collections in get() function.
Here is Example to use multiple collection names for one schema:
const coordinateSchema = new Schema({
lat: String,
longt: String,
name: String
}, {collection: 'WeatherCollection'});
const windSchema = new Schema({
windGust: String,
windDirection: String,
windSpeed: String
}, {collection: 'WeatherCollection'});
//Then define discriminator field for schemas:
const baseOptions = {
discriminatorKey: '__type',
collection: 'WeatherCollection'
};
//Define base model, then define other model objects based on this model:
const Base = mongoose.model('Base', new Schema({}, baseOptions));
const CoordinateModel = Base.discriminator('CoordinateModel', coordinateSchema);
const WindModel = Base.discriminator('WindModel', windSchema);
//Query normally and you get result of specific schema you are querying:
mongoose.model('CoordinateModel').find({}).then((a)=>console.log(a));
In Short,
In mongoose you can do something like this:
var users = mongoose.model('User', loginUserSchema, 'users');
var registerUser = mongoose.model('Registered', registerUserSchema, 'users');
This two schemas will save on the 'users' collection.
For more information you can refer to the documentation: http://mongoosejs.com/docs/api.html#index_Mongoose-model or you can see the following gist it might help.
Hope this may help you. You need to modify according to your requirements.

Multiple schema in a file not working

I have two schema in singel schema.js file
var mongoose = require('mongoose');
var user = new mongoose.Schema({
name: String,
add: String,
role: String
});
var Organizationn = new mongoose.Schema({
name: String,
add: String,
name:String
});
module.exports = {
user: user,
Organizationn: Organizationn
};
accessing it like
var models = require("../models/schema");
models.user.findOne()
it says findone is not a function
whereas If i use singel user in a file it is working.
I have gone through this link and did export like above
cant get data from database after multiple schema declared (mongoose + express + mongodb
but not working
any idea?
Thanks
With the help of #anthony I figure out the issue
I need to do the below
module.exports = {
user: mongoose.model('user', user),,
Organizationn: mongoose.model('Organizationn', Organizationn)
};
If you exports more than one file than you will have to import with curly braces { schema1 }
var mongoose = require('mongoose');
var user = new mongoose.Schema({
name: String,
add: String,
role: String
});
var organization = new mongoose.Schema({
name: String,
add: String,
name:String
});
const userSchema = mongoose.model('users', user),
const organizationSchema = mongoose.model('organizations', organization)
module.exports = { User: userSchema, Organization: organizationSchema }
and then import
var { User } = require("../models/schema");
var { Organization } = require("../models/schema");
User.findOne()
Organization.findOne()
Try to look at it in this abstract way:
A mongoose.Schema is basically just an object.
A mongoose.model is a class that you customize with your schema object.
In other words, mongoose.model has all the database functions attached to it, the schema by itself doesn't.

Mongoose - inserting subdocuments

I have a user model, and a log model. The log model is a subdocument of user model. So in my user model I have:
var mongoose = require('mongoose');
var Log = require('../models/log');
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
Log
]
});
Then in my 'Log' model I have:
var mongoose = require('mongoose');
var logSchema = new mongoose.Schema({
logComment: {
type: String,
},
});
module.exports = mongoose.model('Log', logSchema);
So upon creation of a 'user', the 'logsHeld' always begins empty. I want to know how to add subdocuments to this user model.
I've tried doing this POST method:
router.post('/createNewLog', function(req, res) {
var user = new User ({
logssHeld: [{
logComment: req.body.logComment
}]
});
user.save(function(err) {
if(err) {
req.flash('error', 'Log was not added due to error');
return res.redirect('/home');
} else {
req.flash('success', 'Log was successfully added!');
return res.redirect('/home');
}
});
});
But this doesn't work. It also includes a 'new User' line, which I don't think I need given this would be for an existing user.
You need to use the logSchema instead of the Log model as your subdocument schema in User model. You can access the schema as follows:
var mongoose = require('mongoose');
/* access the Log schema via its Model.schema property */
var LogSchema = require('../models/log').schema; // <-- access the schema with this
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [LogSchema]
});
Picking up from your comments in another answer where you are facing another issue
WriteError({"code":11000,"index":0,"errmsg":"E11000 duplicate key
error index: testDB.users.$email_1 dup key:
you are getting this because there's already a document in your users collection that has most probably a null value on the email field. Even though your schema does not explicitly specify an email field, you may have an existing old and unused unique index on users.email.
You can confirm this with
testDB.users.getIndexes()
If that is the case and manually remove the unwanted index with
testDB.users.dropIndex(<index_name_as_specified_above>)
and carry on with the POST to see if that has rectified the error, I bet my $0.02 that there is an old unused unique index in your users collection which is the main issue.
Try using logSchema which references only the subdocument schema, Log refers to the entire contents of ../models/log
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
logSchema
]
});
Documentation: http://mongoosejs.com/docs/subdocs.html
Try push to insert item in array in mongoose
var user = new User;
user.logssHeld.push({
logComment: req.body.logComment
});
user.save(function(err, doc) {
//DO whatever you want
});
see the docs here

How to 'require' a database schema in nodejs

What is the best way to require a mongoose Schema in nodejs?
Originally I had these inside the app.js file but that is getting a bit large and unwieldy with more models.
Now I want to move them into a models folder and use Model = require('./models/model') to import them into app.js
How do I get it such that Model is populated with the actual model?
(exports = mongoose.model(...) fails and gives me a blank object; exports.model = mongoose.model(...) requires me to do Model.model to access it -- neither of these are the desired behavior)
===
Edit1
So basically I have taken
var mongoose = require('mongoose');
var Schema = mongoose.Schema, ObjectId = Schema.ObjectId;
var UserSchema = new Schema({
username: String,
password: String,
first_name: String,
last_name: String,
email: String
});
User = mongoose.model('User', UserSchema);
and put it into ./models/user.js
How do I get it such that its the equivalent of having this in the app.js?
In your app.js server file, include the model.js file like this:
var Model = require('./models/model'); //whatever you want to call it
You can then instantiate it in your server file like this:
//Initiate the Business API endpoints
var model = new Model(mq, siteConf);
model.getUser(id, function() {
// handle result
});
----
Then in your file you place in models folder named model.js (or whatever you want) you can set it up like this:
var mongoose = require('mongoose');
//MongoDB schemas
var Schema = mongoose.Schema;
var User = new Schema({
username: String,
password: String,
first_name: String,
last_name: String,
email: String
});
var UserModel = mongoose.model('User', User);
// your other objects defined ...
module.exports = function(mq, siteConf) {
//MongoDB
mongoose.connect(siteConf.mongoDbUrl);
// ------------------------
// READ API
// ------------------------
// Returns a user by ID
function getUser(id, found) {
console.log("find user by id: " + id);
UserModel.findById(id, found);
}
// Returns one user matching the given criteria
// mainly used to match against email/login during login
function getUserByCriteria(criteria, found) {
console.log("find user by criteria: " + JSON.stringify(criteria));
UserModel.findOne(criteria, found);
}
// more functions for your app ...
return {
'getUser': getUser,
'getUserByCriteria': getUserByCriteria
};
};

Resources