Mongoose findOne.populate scope issue - javascript

There is a array of user IDs in currentUser.follow. Each user has posts with referenceId of PostSchema . Now I want to populate each user's post and store it in an array[userArray]. But due to scope issue the array remains empty. Please show me how I can get all the users with their post in the Array[userArray]
app.js
app.get("/", isLoggedIn, function(req, res){
var currentUser =req.user;
var userArray=[];
for(let fol of currentUser.follow){
User.findById(fol).populate("posts").exec(function(err, user){
if(err){
console.log(err);
}else{
console.log(user); // a user with populated posts
userArray.push(user);
console.log(userArray); //stores user but posts is not populated
}
});
}
console.log(userArray); // empty array
});
User Schema
var mongoose =require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
name: String,
email: String,
username: String,
password: String,
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Post"
}
],
follow: [String]
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
Post Schema
var mongoose =require("mongoose");
var PostSchema = new mongoose.Schema({
text: String,
image: String,
author:{
id:{
type: mongoose.Schema.Types.ObjectId,
ref : "User"
},
username: String
},
createdAt: {type:Date, default:Date.now}
});
module.exports= mongoose.model("Post", PostSchema);

Because User.findById is asynchronous so the second console.log(userArray); will excute before the result pushed to userArray.
There is a better way to do this with $in operator and async/await:
app.get("/", isLoggedIn, async function(req, res){
try {
var currentUser = req.user;
var userArray = await User.find({_id: {$in: currentUser.follow}}).populate("posts");
console.log(userArray);
} catch(err) {
console.log(err);
}
});

Related

Trying to populate my user model and getting a Type Error

In my program I want to populate my index page with a model called a group. Previously I just showed all the groups that existed in the database, but now I want to only show the groups that the user who is logged in is associated with.
Here are the models:
Group Model
var mongoose = require("mongoose");
var groupSchema = new mongoose.Schema({
name: String,
thumbnail: String,
description: String,
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
inviteCode: String,
images: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Image"
}
],
users: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
] });
module.exports = mongoose.model("Group", groupSchema);
User Model
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
username: String,
password: String,
groups:
[
{
type: mongoose.Schema.Types.ObjectId, //referencing model by id
ref: "Group" //name of the model
}
],
images:
[
{
type: mongoose.Schema.Types.ObjectId, //referencing model by id
ref: "Image" //name of the model
}
]
});
UserSchema.plugin(passportLocalMongoose); //add in local mongoose methods to user
module.exports = mongoose.model("User", UserSchema);
My Index Route:
//Index Route
router.get("/", middleware.isLoggedIn, function(req, res){
var user = req.user;
user.populate("groups").exec(function(err, allGroups){
if(err){
console.log(err);
} else {
res.render("groups/show", {groups: allGroups});
console.log(allGroups);
}
});
});
And this is the error I get:
TypeError: user.populate(...).exec is not a function
I am not sure why I cant use the populate method with my user model, can someone explain me an alternative to achieve the desired outcome. Thank you.
I think the problem is that req.user is not a schema, so .populate is not a method carried by that variable in its object prototype. Hence the terminal telling you it's not a function.
You have to require the User schema like this in your index route:
const User = require("./models/user");
Then find the user by its id then populate it:
//Index Route
router.get("/", middleware.isLoggedIn, function(req, res){
var user = req.user;
User.findById(req.user._id, function(err, foundUser) {
let user = foundUser;
user.populate("groups").exec(function(err, allGroups){
if(err){
console.log(err);
} else {
res.render("groups/show", {groups: allGroups});
console.log(allGroups);
}
});
});
});
Let me know if it works!

Mongoose Foregin Key mapping

I'm new to MongoDB/Mongoose and trying to figure out how to map relationships between Schema. I don't think issue is with .populate(). At creation of new user and clients, I do not see the relationship reflected in collection
User (login via local/social) has many Clients.
A set of Clients belong to 1 User
Is this the correct way to declare foreign key? {type: Schema.Types.ObjectId, ref: 'Client'}
Should both Schema have the each other's foreign key to relate to one another?
Is there any additional code required when creating User/Client in order for the data from foreign key to show up? I read something about populate()
User
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
local: {
id: String,
email: String,
password: String,
name: String,
mobile: String,
clients: {type: Schema.Types.ObjectId, ref: 'Client'}
},
google: {
id: String,
token: String,
email: String,
name: String,
clients: {type: Schema.Types.ObjectId, ref: 'Client'}
}
});
module.exports = mongoose.model('User', userSchema);
Client
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var clientSchema = new Schema({
id: String,
firstname: String,
lastname: String,
mobile: String,
user: {type: Schema.Types.ObjectId, ref: 'User'}
});
module.exports = mongoose.model('Client', clientSchema);
Create User
app.post("/api/user", function (req, res) {
const user = req.body;
console.log(user);
User.findOne({ 'local.email': user.email },
function (err, result) {
if (err) {
console.log(err);
handleError(err, res);
return;
}
if (result) {
res.status(500).send("Email already exists in database");
} else {
var newUser = new User();
newUser.local.password = generateHash(user.password);
newUser.local.email = user.email;
newUser.local.name = user.name;
newUser.local.mobile = user.mobile;
newUser.save(function (err, result) {
res.status(201).send("User added to database");
});
}
});
});
Create Client
app.post("/api/client", function (req, res) {
const client = req.body;
console.log(client);
Client.findOne({
$and: [
{ firstname: client.firstname },
{ lastname: client.lastname }
]
},
function (err, result) {
if (err) {
console.log(err);
handleError(err, res);
return;
}
if (result) {
res.status(500).send({msg:"Client already exists in database"});
} else {
var newClient = new Client();
newClient.firstname = client.firstname;
newClient.lastname = client.lastname;
newClient.mobile = client.mobile;
newClient.save(function (err, result) {
res.status(201).send("Client added to database");
});
}
});
});

Mongoose 1:Many Parent Relation Doesn't Save (says undefined)

I am new to express/mongoose and trying to implement User-Post relationship.Aka 1:Many.
I have two models,
// *models/user.js
var mongoose = require('mongoose');
var userSchema = mongoose.Schema({
email: {type: 'string'},
password: {type: 'string'},
posts: [{type: mongoose.Schema.Types.ObjectId, ref: 'Post'}]
});
module.exports = mongoose.model('User', userSchema);
// *models/post.js
var mongoose = require('mongoose');
var postSchema = mongoose.Schema({
user : { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
body: String,
title: String
});
module.exports = mongoose.model('Post', postSchema);
server.js,
Post = require('./models/post');
User = require('./models/user');
app.post('/api/posts',(req,res)=>{
User.findOne({email: "valid_email"},(err, user)=>{
var post = {
title: "Post 1 Title",
body: "Post 1 body",
user: user._id
}
Post.create(post, (err, post)=>{
res.send(post);
});
});
});
Now, this approach is working for saving the Post which belongs to user with email "valid_email".I can reach out it's user by populating.
app.get('/post', (req,res)=>{
Post.findOne(title: "Post 1 title")
.populate('user')
.exec(function (err, user) {
if (err) throw err;
console.log(user._id, user.email);
res.end();
});
});
I thought generating a Post in the callback of finding a User would automatically push it to User's posts.Not only it is not how it works, i can't push manually to "user.posts".
It says can't "push" to undefined.When i console.log(user.posts) i get undefined.
How is it that i can generate a Post belongsTo a User, then i can populate the user just by it's id, but can't push a Post to User? It gives undefined "user.posts" ?
!!! I got it working.
app.post('/api/posts', (req,res)=>{
User.findOne({id: _some_user_id}, (err,user)=>{
var poster = user;
var post = {title: req.body.title, body: req.body.body, category: req.body.category, user: poster}
Post.create(post, (err,post)=>{
res.send(post);
poster.posts.push(post);
poster.save();
});
});
});

passport User is not a function

I keep getting the same error "User is not a function" when I call my API method.
Has anybody got an ideas why this might be.
Api method:
//need to export the api methods.
var User = require('../models/user');
var passport = require('passport');
module.exports.create = function(req, res) {
//TODO: error checking.
var user = new User();
console.log(req);
user.firstName = req.body.firstName;
user.secondName = req.body.secondName;
user.email = req.body.email;
user.setPassword(req.body.password);
user.save(function(err) {
res.status(200);
});
};
user model:
var mongoose = require('mongoose');
var crypto = require('crypto');
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
hash: String,
salt: String
});
userSchema.methods.setPassword = function(password){
};
userSchema.methods.validPassword = function(password) {
};
mongoose.model('User', userSchema);
Let me know if I need to enter any more files.
Thanks
You need to export the mongoose model you created at the end of the User Model file. Something like
module.exports = mongoose.model('User', userSchema);

Creating dynamic Mongoose models with prefix

I would like to create mongoose model dynamically with a prefix variable.
I have a First UserSchema
var UserSchema = new Schema({
username: String,
blogs : [{type: mongoose.Schema.Types.ObjectId, ref: 'Blog' }],
)};
module.exports = mongoose.model('User', UserSchema);
And a BlogShema
var BlogSchema = new Schema({
blogName: String,
posts : [{type: mongoose.Schema.Types.ObjectId, ref: prefix + 'Post' }]
)};
module.exports = mongoose.model('Blog', BlogSchema);
Then a PostSchema
var PostSchema = new Schema({
blog: { type: String, ref: 'Blog' },
title: String,
content: String
)};
module.exports = mongoose.model(prefix + 'Post', PostSchema);
Each Schema is on separate js files:
posts.server.model.js
blogs.server.model.js
users.server.model.js
I would like the prefix variable in mongoose.model(prefix + 'Post', PostSchema); to get the value of username String from UserSchema which passed form a signup form through
require('../../models/users.server.model.js');
require('../../models/blogs.server.model.js');
require('../../models/posts.server.model.js');
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
mongoose = require('mongoose'),
User = require('mongoose').model('User'),
Blog = require('mongoose').model('Blog'),
Post = require('mongoose').model(prefix + 'Post');
passport.use('local-signup', new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done) {
process.nextTick(function() {
User.findOne({ username : username }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'Username is already taken.'));
} else {
var newUser = new User();
newUser.username = username;
newUser.password = password;
newUser.email = req.body.email;
newUser.save(function(err) {
if (err)
throw err;
var site = new Site({user : newUser.username, siteTitle: newUser.username});
site.save(function(err) { // create website
if (err) {
return next(err);
} else {
newUser.sites.push(site); // push site'id in sites field in user
newUser.save(); // save user after site'id has been push
for (var i=0; i<basePages.length; i++) { // create pages from base.json file
var page = new Page(basePages[i]);
page.save(function(err, page) { // create page
if (err) {
return next(err);
} else {
site.pages.push(page); // push page'id in pages field in site
site.save(); // save site after pages'id has been push
};
});
};
return done(null, newUser);
};
});
});
};
});
});
}));
For resume, If signup username is john during signup I would like to create a johnpost collection john posts.

Categories

Resources