Use populate() for two different schemas in MongoDB - node.js

I have two MongoDB collections - comments
var mongoose = require('mongoose');
var CommentSchema = new mongoose.Schema({
body: String,
author: String,
upvotes: {type: Number, default: 0},
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' }
});
mongoose.model('Comment', CommentSchema);
and users
var mongoose = require('mongoose');
var UserSchema = new mongoose.Schema({
userName: String,
userJobRole: String,
userEmail: String,
userPhone: String,
userTimeZone: String,
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' }
});
mongoose.model('User', UserSchema);
I want to use populate for each of these schemas in my get request. One for users and one for comments from these models.
router.get('/profiles/:profile', function(req, res, next) {
req.post.populate('users', function(err, post) {
if(err) { return next(err) }
res.json(post);
});
});
I can only figure out how to call one.
Does Mongoose allow you to populate from two schemas?

In order to populate multiple paths, you can pass a space delimited string of path names to the populate method on any document as follows:
Story
.find(...)
.populate('fans _creator') // space delimited path names
.exec()
This is taken directly from the Mongoose docs http://mongoosejs.com/docs/populate.html

Related

Error when using _id as a property type in a Mongoose Schema

I am learning MongoDB and mongoose at the moment. I have a Archive and a User schema in mongoose:
archive.js
var mongoose = require('mongoose');
var User = require('../users/user');
var notesSchema = new mongoose.Schema({
author: User.userId,
text: String,
files:[String]
});
var archiveSchema = new mongoose.Schema({
name: String,
priority: String,
deadline: Date,
status: String,
assigned_memnbers: [User.userId],
notes: [notesSchema],
});
archiveSchema.virtual('archiveId').get(function() {
return this._id;
});
module.exports = mongoose.model('Archive', archiveSchema);
user.js:
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
username: String,
mail: String,
bio: String,
password: String
});
userSchema.virtual('userId').get(function() {
return this._id;
});
module.exports = mongoose.model('User', userSchema);
When I run my server i get the error
TypeError: Invalid value for schema path `author`, got value "undefined"
The the problem comes from author: User.userId, but I don't know how to make a reference between the two tables.
For reference, here is what my complete db design more or less looks like:
Any input on how to solve this problem or improve the overall design is welcome. Thanks you.
I think what you're talking about is a reference to other collection:
author: { type: Schema.Types.ObjectId, ref: 'User' }
and
assigned_members: [{ type: Schema.Types.ObjectId, ref: 'User' }]
should work fine.
Source: Mongoose population
I faced the same issue.I had imported a module, It was just not exporting from another module. so I have added:
exports.genreSchema = genreSchema;

findById in Mongoose on a subdocument

I am attempting a findById in Mongoose on a subdocument....[posts]
How do i findById one specific [post] inside user?
var postSchema = new mongoose.Schema({
title: String,
content: String
});
var userSchema = new mongoose.Schema({
email: String,
name: String,
posts: [postSchema]
});
You could use the dot notation something like this
unique_id = req.params.id
const uniquePost = User
.find({'posts._id':unique_id })
or if you hade a schema like this nesting
var userSchema = new mongoose.Schema({
email: String,
name: String,
posts: {
posts: postSchema
}
});
you coulld again use dot notation to find the deeply nested id
like so
const uniquePost = User
.find({'posts.posts._id':unique_id })

Mongoose findByIdAndUpdate

I trying to edit and update a form using mongoose. The code seems fine to me, but it doesn't work. I have tried so many ways but the updated version is still the same, I uses a put route to send the form, when I output req.body.studentInfo to the console, it is correct, but the update remains the same. Please help
This is my schema
var mongoose = require("mongoose");
var uniqueValidator = require('mongoose-unique-validator');
var passportLocalMongoose = require("passport-local-mongoose");
var mongoose = require("mongoose");
var UserSchema = new mongoose.Schema({
studentInfo: {
first_name: String,
middle_name: String,
last_name: String,
street: String,
town: String,
city: String,
region: String,
country: String,
studentId: String,
day: Number,
month: String,
year: Number,
},
username: {type: String, required:true, unique:true},
passport: String
});
UserSchema.plugin(uniqueValidator);
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("StudentInfo", UserSchema);
This is my App.js
app.put('/:id', function(req,res){
StudentInfo.findByIdAndUpdate(req.params.id, {$set: req.body.studentInfo}, function(err, updated){
console.log(req.params.id);
console.log(req.body.studentInfo);
if(err) {
console.log(err);
}
else {
res.redirect('/' + req.params.id);
}
});
});
The studentInfo is an object that contains the names of each variables in my form which I name was studentInfo[name of variable]. Please help
It should be specified that mongoose should return the updated document - by default it returns the original (this is also the behavior of mongodb). I think that if the code gets changed to this:
StudentInfo.findByIdAndUpdate(req.params.id, {$set: req.body.studentInfo}, { new: true }, function(err, updated){
...
});
you will receive the updated document in the callback.
As #Denny mentioned in his answer, mongoose will not return the updated document in the callback until you pass {new : true } option.
For Details and available options check findByIdAndUpdate Docs

Mongoose remove document with references

I have two Schemas, eventSchema and personSchema as shown below:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var eventSchema = Schema({
title : String,
location : String,
startDate : Date,
endDate : Date
});
var personSchema = Schema({
firstname: String,
lastname: String,
email: String,
dob: Date,
city: String,
eventsAttended: [{ type: Schema.Types.ObjectId, ref: 'Event' }]
});
var Event = mongoose.model('Event', eventSchema);
var Person = mongoose.model('Person', personSchema);
How can I remove all eventsAttended from a deleted Person?
For example, if I remove a Person then I expect that all events assigned to that Person will be removed.
This is my code:
Person.findOneAndRemove({_id: req.body._id}, (err, response) => {
// remove the events assigned to this person
})
With mongoose you can use pre and post middleware on your schemas:
personSchema.post('remove', removeLinkedDocuments);
Then in the removeLinkedDocuments callback, you can remove all linked documents:
function removeLinkedDocuments(doc) {
// doc will be the removed Person document
Event.remove({_id: { $in: doc.eventsAttended }})
}
Note the middleware is only called for the following methods (refer to the linked documentation for details):
count
find
findOne
findOneAndRemove
findOneAndUpdate
update
To remove the documents 'manually' in your callback, you might do
Person.findOneAndRemove({_id: req.body._id}, (err, response) => {
// note that if you have populated the Event documents to
// the person documents, you have to extract the id from the
// req.body.eventsAttended object
Event.remove({_id: { $in: req.body.eventsAttended }}, (err, res) => {
...
})
})

mongoose - storing an array of ids in mongoDB at storage time, but getting entire objects back at runtime?

I am trying to setup a mongoose model of what I want in my mongodb instance.
here is the code I have for a user type so far.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports = mongoose.model('User', new Schema(
{
username: String,
userType: int,
tagline: String,
friends: <Not sure what to do here>
}));
Essentially, I want to only store the ids of other users in here at insert time etc, but when I query to GET this user, I want to actually get the json that would have the various users I want to get back.
Mongoose provides a mechanism for referencing other collections and populating them. I'm making the assumption the _ids in friends are other Users so you can define your schema as
module.exports = mongoose.model('User', new Schema(
{
username: String,
userType: int,
tagline: String,
friends: [{type: ObjectId, ref: 'User'}]
}));
And then you can use the built in populate method in mongoose to retrieve the actual documents and not just the _ids
User
.findOne({ username: username })
.populate('friends')
.exec(function (err, user) {
if (err) return handleError(err);
console.log(user.friends);
});
I need to use Population. So you define your fields as ref:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports = mongoose.model('User', new Schema({
username: String,
userType: int,
tagline: String,
friends:[{type: Schema.ObjectId, ref: 'User'}]
}));
And could fetch your friends as array of objects via .populate method:
User.findById(id)
.populate('friends')
.exec(function (err, user) {
if (err) throw err;
// user.friends is array of users
console.log(user.friends)
})

Resources