Populating count of records from other collection with Mongoose - node.js

I have 2 Mongoose models, Book and Users. i want to do that: When find a book, i want to get the count of current book users.
this is book model:
var mongoose = require('mongoose');
var Users = require('../users');
var schema = new mongoose.Schema({
book_name: String,
book_publisher: String
});
var book = mongoose.model('book', schema);
module.exports = book;
this is users model:
var mongoose = require('mongoose');
var Book = require('../book');
var schema = new mongoose.Schema({
user_name: String,
book_id: String
});
var users = mongoose.model('users', schema);
module.exports = users;
i fetch a book like this:
Book.find({book_name:name).exec(
function(err, book) {
if (err) {
throw err;
}
var new_book = book;
}
);
right now tis code fetch a book, but i want to populate count of users inside Users model and add them to the new fetched book object.
i read this document but i can't accomplish that:
Population

User = new mongoose.Schema({
//existing user properties
owned_books: [{type: mongoose.Schema.Types.ObjectId, ref: 'book'}]
}}
var users = mongoose.model('users', User);
var schema = new mongoose.Schema({
book_name: String,
book_publisher: String,
owner_ids: [{type: mongoose.Schema.Types.ObjectId, ref: 'users'}]
});
var book = mongoose.model('book', schema);
You'll need to update both schema when you add people to books or books to people. To get the current book users, just find the book and then get length of it's owner_ids field.

What you want to do is usually known as reverse lookup. Luckily, someone has already created a module for that. It doesn't seem like its a very commonly used module, but you could see if it fits your needs: reverse-populate.

Related

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.

mongoose db populate doesn't seem to work

So this is how my models are:
groupModel.js
var Schema = mongoose.Schema;
var groupSchema = new Schema({
uuid: String,
users: [{type: Schema.Types.ObjectId, ref:'users'}]
});
var Groups = mongoose.model('groups', groupSchema);
module.exports = Groups;
userModel.js
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
var userSchema = new Schema({
username: String,
password: String,
firstname: String,
lastname: String,
email: String,
emailVerified: Boolean
});
var Users = mongoose.model('users', userSchema);
module.exports = Users;
and this is the api I am hoping to get it to work:
/* GET /group/list/:id listing. */
router.get('/list/:id', function(req, res) {
Group.findOne({uuid :
req.params.id}).populate('Users').exec(function(err, group){
if(err) throw err;
console.log(group);
res.status(200).send(group);
});
});
this is the response I get back:
{"_id":"5aaf52b4165e97aae4a0b42c","uuid":"iyzIc","__v":0,"users":
["58f5acae4733ae5f64XXXXea","590a663c2a32ad28e0XXXX29"]}
For some reason I am not able to replace the id's with actual data for the users. I was hoping to get user related details instead of ids for the two users. Am I doing something wrong? I am trying to learn nodejs and was hoping some nodejs expert will be able to find my silly mistake.
EDITED:
changing .populate('Users') -> .populate('users') fixed the issue.
Users being capitalized in populate is the problem!

How to get a list of available Mongoose Discriminators?

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.

Plugin usage with nested subdocuments in mongoose

I have a schema in mongoose like this:
var subtopicSchema = new schema({
name:String
})
var topicSchema = new schema({
name:String,
subtobpics:[subtopicSchema]
});
var subjectSchema = new schema({
name:String,
topics:[topicSchema]
})
var courseSchema = new schema({
name:{type:String,unique:true},
subjects:[subjectSchema]
});
And then I am using a 'unique validator plugin' like this:
courseSchema.plugin(uniqueValidator, { message: 'unique' });
So here is what i want to achieve:
All courses should be unique
All subjects within a particular course needs to be unique
All topics within a particular subject to needs be unique
All subtopics within a particular topic to needs be unique
So the question is: Is the current setup gonna work for the above four requirements?
If yes, why?
If not, How?

is it possible to reference a subdocument schema in mongoose?

is it possible to reference a sub document schema in mongoose ?
just like below
var sectionSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true}
});
var courseSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true},
sections:[sectionSchema]
});
var studentSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true},
course:{type:mongoose.Schema.Types.ObjectId,ref: 'courseSchema'},
section:{type:mongoose.Schema.Types.ObjectId,ref: 'sectionSchema'},
contactnumber:{type:String,required:true},
parentname:{type:String,required:true}
});
var schoolSchema = mongoose.Schema(
{
id:{type:String,required:true},
name:{type:String,required:true,unique:true},
address:{type:String,required:true},
year:{type:String,required:true},
contactnumber:{type:String,required:true},
courses:[courseSchema],
students:[studentSchema]
});
var School = mongoose.model('School',schoolSchema);
in the above model i have section inside course which is inside school document.
i have students schema which is inside school document i want course to point to course schema and section to point to section schema.so is it possible to refer a sub document schema in mongoose.

Resources