Reputation: 6568
I have two mongoose DB schema, a User
and a Profile
:
var userSchema = new mongoose.Schema({
username: String,
password: String,
type: String
});
userSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", userSchema);
var profileSchema = new mongoose.Schema({
username: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
email: {
type: String,
default: ""
},
skill: {
type: String,
default: ""
}
});
module.exports = mongoose.model("Profile", profileSchema);
I am first registering and authenticating a user using passport-js, and if this is successful, I then want to create populate the Profile
db with username
and type
. I will then allow users to update this Profile
db (but not the Users
). Following the docs I am trying to use .populate
, to create an entry in Profile
with the same information as in User
:
router.post("/signup", function(req, res) {
var newUser = new User({username: req.body.username, type: req.body.type});
User.register(newUser, req.body.password, function(err, user){
if(err){
console.log(err.message);
return res.render("signup");
}
passport.authenticate("local")(req, res, function(){
Profile.findById(newUser._id).populate("username").exec(function(err, foundUser){
if(err){
console.log("Problem populating the profiles DB");
}
else{
console.log("New user:" + newUser._id);
res.redirect("profile/" + newUser._id);
}
});
});
});
});
This passes without error, but my Profiles
db is empty.
Can anyone see what I'm doing wrong here?
I have also tried (within the same route):
Profile.create(newUser, function(err, newlyCreated){
if(err){
console.log(err);
} else {
console.log("Added user to profile db:" + newUser._id);
console.log("New user:" + newUser._id);
res.redirect("profile/" + newUser._id);
}
});
But this fails with error:
{ DocumentNotFoundError: No document found for query "{ _id: 5c6d9512a4a301b73b565681 }"
Another approach I'm trying is this:
Profile.create({username:req.body.username, type: req.body.type}, function(err, pro){
if(err){
console.log("Profile error: " + err);
} else {
console.log("Added user to profile db:" + newUser._id);
console.log("New user:" + newUser._id);
res.redirect("profile/" + newUser._id);
}
});
Which passes, but produces an entry in Profiles
with an _id
different from the corresponding entry in Users
.
Would anyone be able to point me in the right direction?
Upvotes: 0
Views: 248
Reputation: 36
Several parts of your code are problematic.
You called newUser._id
however newUser is an instantiation of the mongoose model User. The _id
field is created by MongoDB when storing a document to the db, so it's logical the field isn't filled when just instantiating an object. It is created when saving it to the db. So you can access the correct _id
on user._id
, with user
coming from the callback.
router.post("/signup", function(req, res) {
var newUser = new User({username: req.body.username, type: req.body.type});
User.register(newUser, req.body.password, function(err, user){
if(err){
console.log(err.message);
return res.render("signup");
}
passport.authenticate("local")(req, res, function(){
Profile.findById(user._id).populate("username").exec(function(err, foundUser){
if(err){
console.log("Problem populating the profiles DB");
}
else{
console.log("New user:" + user._id);
res.redirect("profile/" + user._id);
}
});
});
});
});
Moreover you have strange parts in your code:
profiles
collection when creating a user. So how do you think it can find an document which wasn't created. .findById
on Profile and passing it an _id
from a User document, whereas it's not an _id
of this db, so there is no document with the queried _id
in this collection. Profile.findOne({username: user.name})
and then try to populate on your field: Profile.findOne({username: user.name}).populate('user')
with profile.user = user._id
when storing the profile. user._id
to find the related documents, so store a unique value to your profile to find it easily.So your schema should look a bit different:
var profileSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
email: {
type: String,
default: ""
},
skill: {
type: String,
default: ""
}
});
and when populated through this call Profile.findOne({user: user._id}).populate('user')
as a result you'll get:
{
user: {
username,
password,
type
},
email,
skill
}
Remember:
user._id
inside your profile.user
attribute.Collection.findById(id)
will look for a document inside the collection with document._id === id
Profile.findOne({user user._id}).populate({path: 'user', select: "-password"})
. This request will remove the password field to reduce data leakage risks.Upvotes: 1