Is that possible, to solve a complex mongoose populate query? - node.js

I have four tables.
#First table
var mongoose=require('mongoose');
var Schema=mongoose.Schema;
#First table
var studentSchema=new Schema({
student_name: { type: String, required: true },
sendKey: { type: String },
created_by: { type:String },
updated_at: { type: Date, default: Date.now },
})
module.exports=mongoose.model('Student',studentSchema);
#Second table
var mongoose=require('mongoose');
var Schema=mongoose.Schema;
var institutionSchema=new Schema({
institution_name: { type: String, lowercase: true },
email: { type:String },
created_by: { type:String },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
})
module.exports=mongoose.model('Institution',institutionSchema);
#third table
var mongoose=require('mongoose');
// var Institution = ('./institution');
var Schema=mongoose.Schema;
var batchSchema=new Schema({
batch_name: { type: String, required: true },
institution: { type: Schema.Types.ObjectId, ref: 'Institution' },
created_by: { type:String },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
})
module.exports=mongoose.model('Batch',batchSchema);
#Fourth Table
var mongoose=require('mongoose');
var Schema=mongoose.Schema;
var batchtudentSchema=new Schema({
student_id: { type: Schema.Types.ObjectId, ref: 'Student', required : true},
batch_id: { type: Schema.Types.ObjectId, ref: 'Batch', required:true},
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
})
module.exports=mongoose.model('BatchStudent',batchtudentSchema);
I have an institution Id. I want to find all students of this institution with Batch details.
Primarily I have tried to.. do that.
Student.find().populate('BatchStudent').pupulate('Batch').populate('Institution').exec((err, docs) => {
console.log(docs)
res.json(
{
data:docs
}
)
})
It is not working.. sending just all student data.. How can I get the data correctlly?

// Student Schema
var mongoose=require('mongoose');
var Schema=mongoose.Schema;
var studentSchema=new Schema({
student_name: {
type: String,
required: true
},
sendKey: {
type: String
},
batchStudent: {
type: Schema.Types.ObjectId,
ref: 'BatchStudent',
}
created_by: {
type:String
},
updated_at: {
type: Date,
default: Date.now
},
})
module.exports=mongoose.model('Student',studentSchema);
// BatchStudent Schema
var mongoose=require('mongoose');
var Schema=mongoose.Schema;
var batchtudentSchema=new Schema({
student_id: {
type: Schema.Types.ObjectId,
ref: 'Student',
required : true
},
batch_id: {
type: Schema.Types.ObjectId,
ref: 'Batch'
},
institution: {
type: Schema.Types.ObjectId,
ref: 'Institution'
}
})
module.exports=mongoose.model('BatchStudent',batchtudentSchema);
// Institution Schema
var mongoose=require('mongoose');
var Schema=mongoose.Schema;
var institutionSchema=new Schema({
institution_name: {
type: String,
lowercase: true
},
email: {
type: String
},
created_by: {
type:String
}
});
module.exports=mongoose.model('Institution',institutionSchema);
If the I removed created_at and updated_at to avoid duplication. Obey DRY principles always (Don't repeat yourself)
If you need to get the document you can simply use Deep Population/Association for that as shown below:
Student.find({}).populate({
path : 'batchStudent',
populate : {
path : 'institution'
}
}).exec(function (err, res) {
// do whatever you need to do here
})

Related

Mongoose(mongoDB) Linking multiple schema's

Im relatively new to MongoDB and Mongoose. Im much used to MySQL so in used to inner joining tables on calls. Ive read a lot that you can link two Mongoose Schemas to achieve the same outcome. How would like like the two schemas together to when I make a call to get a chore by id it'll return the chore and then for the assignedTo & createdBy have the user scheme data for the said userId?
Chore Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ChoreSchema = new Schema({
title: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
time: {
type: Number,
required: true
},
reaccurance: {
type: [{
type: String,
enum: ['Daily', 'Weekly', 'Bi-Weekly', 'Monthly']
}]
},
reward: {
type: Number,
required: true
},
retryDeduction: {
type: Number,
required: false
},
createdDate: {
type: Date,
default: Date.now
},
createdBy: {
type: String,
required: true
},
dueDate: {
type: Date,
required: true
},
status: {
type: [{
type: String,
enum: ['new', 'pending', 'rejected', 'completed', 'pastDue']
}],
default: ['new']
},
retryCount: {
type: Number,
default: 0,
required: false
},
rejectedReason: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
assignedTo: {
type: String,
required: false,
default: ""
}
});
let Chores = module.exports = mongoose.model('Chores', ChoreSchema);
module.exports.get = function (callback, limit) {
Chores.find(callback).limit(limit);
};
User Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
role: {
type: [{
type: String,
enum: ['Adult', 'Child']
}]
},
birthday: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
balance: {
type: Number,
required: true,
default: 0.00
}
});
let Users = module.exports = mongoose.model('Users', UserSchema);
module.exports.get = function (callback, limit) {
Users.find(callback).limit(limit);
};
Im trying to link ChoreSchema.createdBy & ChoreScheme.assignedTo by UserSchema._id
How I make the call in Node.js:
exports.index = function(req, res) {
Chore.get(function(err, chore) {
if (err)
res.send(err);
res.json({
message: 'Chore List',
data: chore
});
});
};
Mongoose has a more powerful alternative called populate(),
which lets you reference documents in other collections.
https://mongoosejs.com/docs/populate.html
Here is how you can link ChoreSchema.createdBy and ChoreScheme.assignedTo by UserSchema._id
var mongoose = require('mongoose');
const { Schema, Types } = mongoose;
var UserSchema = new Schema({
firstName: { type: String, required: true },
...
})
var ChoreSchema = new Schema({
title: { type: String, required: true },
...
//The ref option is what tells Mongoose which model to use during population
assignedTo: { type: Types.ObjectId, ref: 'Users' },
createdBy: { type: Types.ObjectId, ref: 'Users' },
})
let Chores = mongoose.model('Chores', ChoreSchema);
let Users = mongoose.model('Users', UserSchema);
Then in your express route handler you can populate assignedTo & createdBy like this
router.get('/chores/:id', function (req, res) {
const choreId = req.params.id;
Chores.find({ _id: choreId })
.populate('createdBy') // populate createdBy
.populate('assignedTo') // populate assignedTo
.exec(function (err, chore) {
if(err) {
return res.send(err)
}
res.json({ message: 'Chore List', data: chore });
});
})

Node.js mongoose model.findOne is not a function

Having an issue with a model. Trying to do a model.findOne(), but I keep getting the error
Error:
TypeError: User.findOne(...).than is not a function
I definitely installed mongoose, but it seems I am no longer importing mongoose or the User model appropriately? Not sure.
User.js (model)
const mongoose = require('mongoose')
const Schema = mongoose.Schema
module.exports = User => {
var UserSchema = new Schema({
name: String,
email: { type: String, unique: true },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
document: String,
profile_picture: String,
ocupation: { type: Schema.Types.ObjectId, ref: 'Ocupation' },
is_admin: { type: Boolean, default: false },
sector: { type: Schema.Types.ObjectId, ref: 'Sector' },
is_manager: { type: Boolean, default: false },
group: { type: Schema.Types.ObjectId, ref: 'Group' },
is_team_leader: { type: Boolean, default: false },
can_start: { type: Boolean, default: true },
isVerified: { type: Boolean, default: false },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
deleted_at: Date,
}, {
toJSON: {
virtuals: true
}
})
UserSchema.virtual('profile_url').get(function() {
return `http://${process.env.HOST}:${process.env.NODE_ENV ? process.env.DEV_PORT : process.env.PORT}/3e002f70cbf8805c904bf1536a22a52e/${this.profile_picture}`
})
return mongoose.model('Users', UserSchema)
}
UserController.js
const User = require('../models/User')
myfunction(req, res) {
const { name, email } = req.body
let checkEmail = await User.findOne({ email })
}
whats wrong?
You're not exporting the model, but a factory(?) function for generating a model. Just remove:
module.exports = User => {
and instead, edit your return statement to:
module.exports = mongoose.model('Users', UserSchema');
Also, side note, it's usually a good idea to define your model in a singular form: User, not Users.
You'll have to create reference to your model & then export that to be used as reference to the Schema
Like this,
const mongoose = require('mongoose')
const Schema = mongoose.Schema
var UserSchema = new Schema({
name: String,
email: { type: String, unique: true },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
document: String,
profile_picture: String,
ocupation: { type: Schema.Types.ObjectId, ref: 'Ocupation' },
is_admin: { type: Boolean, default: false },
sector: { type: Schema.Types.ObjectId, ref: 'Sector' },
is_manager: { type: Boolean, default: false },
group: { type: Schema.Types.ObjectId, ref: 'Group' },
is_team_leader: { type: Boolean, default: false },
can_start: { type: Boolean, default: true },
isVerified: { type: Boolean, default: false },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
deleted_at: Date,
}, {
toJSON: {
virtuals: true
}
})
UserSchema.virtual('profile_url').get(function() {
return `http://${process.env.HOST}:${process.env.NODE_ENV ? process.env.DEV_PORT : process.env.PORT}/3e002f70cbf8805c904bf1536a22a52e/${this.profile_picture}`
})
var User = mongoose.model('Users', UserSchema)
module.exports = User;

Load post from Followers in Nodejs and Mongoose

I have a schema for post like below, but am having problem fetching post from my followers. i have also tried using but all to no avail. please help
I have a schema for post like below, but am having problem fetching post from my followers. i have also tried using but all to no avail. please help
I have a schema for post like below, but am having problem fetching post from my followers. i have also tried using but all to no avail. please help
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema =new Schema({
user: {
type: Schema.Types.ObjectId,
ref:'users'
},
text:{
type:String,
required: true
},
name:{
type:String
},
avatar:{
type:String
},
likes:[
{
user:{
type: Schema.Types.ObjectId,
ref: 'users'
}
}
],
comments:[
{
user:{
type: Schema.Types.ObjectId,
ref: 'users'
},
text:{
type:String,
required: true
},
name: {
type: String
},
avatar: {
type: String
},
date:{
type:Date,
default: Date.now
},
likes: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
}
}
],
}
],
reposter: [
{
user: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
date: {
type: Date,
default: Date.now
}
}
],
numberOfRepost: { type: Number, default: 0 },
date: {
type: Date,
default: Date.now
}
});
module.exports = Post = mongoose.model('post', PostSchema);
First of all, you should rethink about mongo-collection design, Here is some tip which it is better to consider.
Use Upper Camel case for declaring mongoose model objects. ( Post, User, ... )
Always put _ before any reference variable. ( _user in Post models )
Separate your collections and avoid redundant properties as much as possible.
Always use Plural of a name for collections. ( posts vs post )
Do not forget to add created and updated property to each collection. ( this hack helps you for logging and investigating your models )
Now, let's look at our new design:
name and avatar are redundant data in the Post model. you can populate them later.
Separate Like, Comment, RePoster from Post model.
Here is the refined Post model object.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema(
{
_user: { type: Schema.Types.ObjectId, ref: 'User' },
text:{ type:String, required: true },
rePostsNum: { type: Number, default: 0 },
// any other meta data which you need
creaetd: Date,
updated: Date
},
{
collection: 'posts',
strict: true,
autoIndex: true
}
);
PostSchema.pre('save', function (next) {
if( this.isNew )
this.created = new Date();
this.updated = new Date();
next();
});
module.exports = Post = mongoose.model('Post', PostSchema);
You can also put _comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }] into the Post model, but think about it! If it is possible to store thousands of comments reference key in _comments array, it is not recommended, it's like technical debt.
Other models:
Comment:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CommentSchema = new Schema(
{
_user: { type: Schema.Types.ObjectId, ref: 'User' },
_post: { type: Schema.Types.ObjectId, ref: 'Post' },
text:{ type:String, required: true },
likesNum: { type: Number, default: 0 },
creaetd: Date,
updated: Date
},
{
collection: 'posts',
strict: true,
autoIndex: true
}
);
CommentSchema.pre('save', function (next) {
if( this.isNew )
this.created = new Date();
this.updated = new Date();
next();
});
module.exports = Comment = mongoose.model('Comment', CommentSchema);
LikePost
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const LikePostSchema = new Schema(
{
_user: { type: Schema.Types.ObjectId, ref: 'User' },
_post: { type: Schema.Types.ObjectId, ref: 'Post' },
creaetd: Date,
updated: Date
},
{
collection: 'likePosts',
strict: true,
autoIndex: true
}
);
LikePostSchema.pre('save', function (next) {
if( this.isNew )
this.created = new Date();
this.updated = new Date();
next();
});
module.exports = LikePost = mongoose.model('LikePost', LikePostSchema);
LikeComment
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const LikeCommentSchema = new Schema(
{
_user: { type: Schema.Types.ObjectId, ref: 'User' },
_comment: { type: Schema.Types.ObjectId, ref: 'Comment' },
creaetd: Date,
updated: Date
},
{
collection: 'likeComments',
strict: true,
autoIndex: true
}
);
LikeCommentSchema.pre('save', function (next) {
if( this.isNew )
this.created = new Date();
this.updated = new Date();
next();
});
module.exports = LikeComment = mongoose.model('LikeComment', LikeCommentSchema);
User
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema(
{
name:{ type:String, required: true },
avatar:{ type:String, required: true },
// any other meta data which you need
creaetd: Date,
updated: Date
},
{
collection: 'users',
strict: true,
autoIndex: true
}
);
UserSchema.pre('save', function (next) {
if( this.isNew )
this.created = new Date();
this.updated = new Date();
next();
});
module.exports = User = mongoose.model('User', UserSchema);
RePost
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const RePostSchema = new Schema(
{
_user: { type: Schema.Types.ObjectId, ref: 'User' },
_post: { type: Schema.Types.ObjectId, ref: 'Post' },
creaetd: Date,
updated: Date
},
{
collection: 'rePosts',
strict: true,
autoIndex: true
}
);
RePostSchema.pre('save', function (next) {
if( this.isNew )
this.created = new Date();
this.updated = new Date();
next();
});
module.exports = RePost = mongoose.model('RePost', RePostSchema);
Welcome back!
Now our new design is fully scalable and guides you to clean and robust code.
Finally, we can query and populate data, Here is two cool sample code:
Load specific user's posts
var mongoose = require('mongoose');
var User = mongoose.model('User');
var Post = mongoose.model('Post');
var Comment = mongoose.model('Comment');
var LikePost = mongoose.model('LikePost');
var LikeComment = mongoose.model('LikeComment');
var RePost = mongoose.model('RePost');
Post
.find({ _user: userId })
.select('_id _user text ...')
.populate({
path: '_user',
select: '_id name avatar ...'
})
.exec(function (err, poats) {
Load specific post's comments
Comment
.find({ _post: postId })
.select('_id _post _user text ...')
.populate({
path: '_user',
select: '_id name avatar ...'
})
.exec(function (err, comments) {
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: {
type: String,
required: true,
},
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar: {
type: String
},
phonenumber: {
type: String,
required: true
},
email: {
type: String
},
resetPasswordToken: {
type: String
},
lastlogin: {
type: Date, default: Date.now
},
passwordUpdated: {
type: Date, default: Date.now
},
resetPasswordExpires: {
type: Date
},
dateofbirth: {
type: Date
},
dateJoined: {
type: Date,
default: Date.now
},
sentRequest: [{
username: { type: String, default: '' },
date: {
type: Date,
default: Date.now
}
}],
request: [{
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
username: { type: String, default: '' },
name: { type: String, default: '' },
phone: { type: String, default: '' },
date: {
type: Date,
default: Date.now
}
}],
friendsList: [{
friendId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
friendName: { type: String, default: '' },
friendUsername: { type: String, default: '' },
friendPhone: { type: String, default: '' },
date: {
type: Date,
default: Date.now
}
}],
followers: [{
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
date: {
type: Date,
default: Date.now
}
}],
blockedContacts: [
{
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
date: {
type: Date,
default: Date.now
}
}],
totalRequest: { type: Number, default: 0 },
repost: [
{
postId: { type: mongoose.Schema.Types.ObjectId, ref: "Post" },
date: {
type: Date,
default: Date.now
}
}
],
accolades: [
{
user: {
type: mongoose.Schema.Types.ObjectId, ref: 'User'
},
remarks: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
followers: [{
user: {
type: mongoose.Schema.Types.ObjectId, ref: 'User'
},
date: {
type: Date,
default: Date.now
}
}],
following: [{
user: {
type: mongoose.Schema.Types.ObjectId, ref: 'User'
},
date: {
type: Date,
default: Date.now
}
}],
})
UserSchema.pre('save', function (next) {
var user = this;
//check if password is modified, else no need to do anything
if (!user.isModified('pass')) {
return next()
}
user.pass = bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
next()
})
module.exports = User = mongoose.model('Users', UserSchema);
This is the user schema

Deep population not working with embedded document

I have three documents as below:
var TrackAudioSchema = new Schema({
track_id: {
type: Number,
},
track_path:{
type:String,
required:'Please upload audio track'
}
});
mongoose.model('TrackAudio', TrackAudioSchema);
var trackSchema = new Schema({
title: {
type: String,
trim:true,
required:'Please fill track title'
},
version : {
type: String,
trim: true,
default: ''
},
trackpath:{
type: Schema.ObjectId,
ref: 'TrackAudio'
},
});
var AlbumSchema = new Schema({
language: {
type: String,
default: '',
trim: true
},
tracks:[trackSchema],
user: {
type: Schema.ObjectId,
ref: 'User'
},
)};
AlbumSchema.plugin(deepPopulate);
mongoose.model('Album', AlbumSchema);
but when I try to populate trackpath from trackSchema using the below query, it doesn't populate:
Album.findById(albumId)
.populate('user','name label').
deepPopulate('tracks.trackpath').
exec(function(err, albumdetail) {
}
Please help.
You're missing:
mongoose.model('Track', TrackSchema);

MongooseJS - population path of subdocuments

I'm having real problems with population on the below schemas. It may not be the best design of models (relatively new to MEAN stacks) but I can get it to populate everything except the Spec model.
// Spec Model
var SpecSchema = new Schema({
time: {
type: Date,
default: Date.now
},
active: {
type: Boolean,
default: 'true'
},
name: String,
desc: String
});
module.exports = mongoose.model('Spec', SpecSchema);
// Thing model
var specsSchema = new Schema({
time: {
type: Date,
default: Date.now
},
spec: {
type: Schema.Types.ObjectId,
ref: 'Spec'
},
value: String,
});
var ThingSchema = new Schema({
time: {
type: Date,
default: Date.now
},
active: {
type: Boolean,
default: true
},
title: String,
specs: [specsSchema]
});
var Thing = mongoose.model('Thing', ThingSchema);
// Set model
var thingsSchema = new Schema({
time: {
type: Date,
default: Date.now
},
active: {
type: Boolean,
default: 'true'
},
thing: {
type: Schema.Types.ObjectId,
ref: 'Thing'
}
});
var SetSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
time: {
type: Date,
default: Date.now
},
active: {
type: Boolean,
default: 'true'
},
title: String,
things: [thingsSchema]
});
var Set = mongoose.model('Set', SetSchema);
The standard population is fine but i cant for the life of me get the model.populate to work and from all the examples and solutions I have looked at I'm unclear as to what the path should be.
Set.findById(req.params.id)
.populate('things.thing')
.populate('user', '_id name')
.exec(function (err, set) {
if(err) { return handleError(res, err); }
if(!set) { return res.send(404); }
Thing.populate(set,{
path:'things.thing.specs.spec',
select: 'name',
model: Spec
}, function(err, set){
if ( err ) return res.json(400, err);
});
return res.json(set);
});
any pointers in the right direction would be much appreciated.
path:'things.thing.specs.spec',
select: 'name',
model: Spec
should be
path:'things.thing.specs.spec',
select: 'name',
model: 'Spec'

Resources