Mongoose Populate Not Working For Me - node.js

I have this schema for users:
var mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
mongoose.Promise = global.Promise;
var userSchema = new mongoose.Schema ({
username: {type: String, required: true, unique: true},
password: {type: String},
role: {type: String, required: true},
confirmed: {type: Boolean, required: true, default: false},
active: {type: Boolean, required: true, default: true},
name: String,
created: {type: Date, default: Date.now},
admin: {type: Boolean, default: false, required: true}
});
userSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", userSchema);
And another schema for companies, where clients refer to an array of users:
var mongoose = require("mongoose");
mongoose.Promise = global.Promise;
var companySchema = new mongoose.Schema ({
name: {type: String, required: true, unique: true},
created: {type: Date, default: Date.now},
active: {type: Boolean, required: true, default: true},
staff: [{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}],
clients: [{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}]
});
module.exports = mongoose.model("Company", companySchema);
I have the below code in my route, but the user information is not being populated into the company object, what am I doing wrong?
// EDIT route
router.get("/:company_id/edit", middleware.checkCompanyOwnership, function(req, res) {
Company.findOne({_id: req.params.company_id}).populate({path: 'clients'}).exec(function(err, company) {
if (err || !company) {
console.log(err);
req.flash("error", err.message);
res.redirect("/");
} else {
console.log("Request to edit company.");
//console.log(company);
res.render("company/edit", {title: "Edit Company", company: company});
}
});
});
This is what I am getting if I console log company:
{ _id: 5a070874b4292914444b6e06,
name: 'ABC',
__v: 1,
clients:
[ { username: 'abcdefg#gmail.com',
_id: 5a070206616810129b5c876a } ],
staff: [],
active: true,
created: 2017-11-11T14:25:56.359Z }
Thanks for your help.

Your company schema should look like this
var companySchema = new mongoose.Schema ({
...
staff: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
clients: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }]
});
See the docs http://mongoosejs.com/docs/populate.html

Related

How do I fetch User post on user timeline?

I have a database containing 3 collections [Users (contains registered users), Userpost (contains the post of the registered users) while Profile (contains their individual profile)].
I was able to link the Profile and Users Schemas to the Userpost Schema with their ObjectId.
What I know at present is how to fetch the Userpost and populate the User and Profile.
What I want to do is to fetch all the post of a single registered user his/her timeline.
What I have tried to the add the Userpost and Profile Schemas to the UserSchema by the ObjectId but each time I make a post, the Userpost on the User collection is always an empty array.
Below are my Schemas please
User Schema
const userSchema = new Schema({
username: {
type: String,
required: true
},
roles: {
User: {
type: Number,
default: 2001
},
Mentor: Number,
Admin: Number
},
password: {
type: String,
required: true
},
userID: {
type: String,
required: true
},
refreshToken: String
});
const User = mongoose.model('user', userSchema);
module.exports = User;
Profile Schema
const ProfileSchema = new Schema({
lastname: {
type: String,
required: true,
},
firstname: {
type: String,
required: true,
},
othernames: {
type: String,
required: true,
},
countries: {
type: String,
required: true,
},
phones: {
type: String,
required: true,
},
User: [{
type: Schema.Types.ObjectId,
ref: 'user',
required: true,
}],
});
const Profile = mongoose.model('profile', ProfileSchema);
module.exports = Profile;
UserPost Schema
const UserpostSchema = new Schema({
post: {
type: String,
required: true
},
Profile: [{
type: Schema.Types.ObjectId,
ref: 'profile',
required: true,
}],
User: [{
type: Schema.Types.ObjectId,
ref: 'user',
required: true,
}]
});
const Userpost = mongoose.model('userpost', UserpostSchema);
module.exports = Userpost;
How I populate User and Profile to the UserPost on API
router.get('/getpost/:id', (req, res) => {
const id = req.params.id;
Userpost.find({_id:id}).populate('User').populate('Profile').exec((err,docs) => {
if(err) throw(err);
res.json(docs);
})
});
How do I fetch the entire post of a user to his timeline?
Kindly help please.
Thanks and regards
This should work for u, In UserPost Schema you have taken array for Profile and User which isn't required, and also instead of Schema use mongoose.Schema every where in model.
User Schema
const mongoose = require('mongoose')
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true
},
roles: {
User: {
type: Number,
default: 2001
},
Mentor: Number,
Admin: Number
},
password: {
type: String,
required: true
},
userID: {
type: String,
required: true
},
refreshToken: String
});
const User = mongoose.model('user', userSchema);
module.exports = User;
Profile Schema
const mongoose = require("mongoose");
const ProfileSchema = new mongoose.Schema({
lastname: {
type: String,
required: true,
},
firstname: {
type: String,
required: true,
},
othernames: {
type: String,
required: true,
},
countries: {
type: String,
required: true,
},
phones: {
type: String,
required: true,
},
User: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: true,
},
});
const Profile = mongoose.model('profile', ProfileSchema);
module.exports = Profile;
UserPost Schema
const mongoose = require("mongoose");
const UserpostSchema = new mongoose.Schema({
post: {
type: String,
required: true,
},
Profile: {
type: mongoose.Schema.Types.ObjectId,
ref: "profile",
required: true,
},
User: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: true,
},
});
const Userpost = mongoose.model("userpost", UserpostSchema);
module.exports = Userpost;

Getter not working on object schema in Mongoose

This is my Mongoose schema:
const mongoose = require('mongoose');
const mongooseUniqueValidator = require('mongoose-unique-validator');
const mongooseTimestamp = require('mongoose-timestamp');
const Schema = mongoose.Schema;
const SectionSchema = new Schema({
name: {type: 'String', required: true},
system: {type: Schema.Types.ObjectId, required: true, ref: 'System'},
subsystem: {type: Schema.Types.ObjectId, required: true, ref: 'Subsystem'},
createdBy: {type: Schema.Types.ObjectId, required: true, ref: 'User'},
allowedUsers: [{
user: {type: Schema.Types.ObjectId},
actions: {type: 'String'},
_id: false
}],
}, {versionKey: 'versionKey'});
SectionSchema.plugin(mongooseTimestamp);
SectionSchema.plugin(mongooseUniqueValidator);
module.exports = mongoose.model('Section', SectionSchema);
the actions parameter save like this:
{"get":true,"post":true,"put":true,"delete":true}
I want to cast it to an object (in Moongoose find result), so I use getter:
const mongoose = require('mongoose');
const mongooseUniqueValidator = require('mongoose-unique-validator');
const mongooseTimestamp = require('mongoose-timestamp');
const Schema = mongoose.Schema;
const SectionSchema = new Schema({
name: {type: 'String', required: true},
system: {type: Schema.Types.ObjectId, required: true, ref: 'System'},
subsystem: {type: Schema.Types.ObjectId, required: true, ref: 'Subsystem'},
createdBy: {type: Schema.Types.ObjectId, required: true, ref: 'User'},
allowedUsers: [{
user: {type: Schema.Types.ObjectId},
actions: {type: 'String',get:toObject}, /* <------- */
_id: false
}],
}, {versionKey: 'versionKey'});
SectionSchema.plugin(mongooseTimestamp);
SectionSchema.plugin(mongooseUniqueValidator);
function toObject (v) { /* <------- */
return JSON.parse(v);
}
SectionSchema.set('toObject', { getters: true }); /* <------- */
SectionSchema.set('toJSON', { getters: true }); /* <------- */
module.exports = mongoose.model('Section', SectionSchema);
But I don't know why getter not working on object schema like allowedUsers.
The find request:
this.model.Section.find(filterParameters, {
_id: 0,
versionKey: 0
}).skip(offset).limit(limit).sort({createdAt: sort})
.populate('system', {_id: 0, name: 1})
.populate('subsystem', {_id: 0, name: 1})
.populate('createdBy', {_id: 0, username: 1})
.populate({
path: 'allowedUsers.user',
model: "User",
select: {username: 1, organization: 1, _id: 0},
populate: {
path: 'organization',
model: 'Organization',
select: {name: 1, _id: 0},
}
})
.exec((error, sections) => {
if (error) {
reject({
statusCode: "422",
message: error
});
} else if ((!sections || sections.length === 0)) {
reject({
statusCode: "404",
message: "No Result"
});
} else {
resolve({
data: sections,
filterParameters: filterParameters
});
}
});
Thanks for any idea...

mongoose document can't access property and can't save

4.11.2, 4.6.1 two version all tested
node js v8.1.2 , mongodb 3.2
(async ()=>{
//配置数据库
console.log(`configure mongodb ...`);
mongoManager.init(app);
mongoManager.connectDB();
console.log(`load models...`);
await mongoManager.loadModels(app.conf.dir.db_schemas);
let dbConnectConfig = app.conf.db.mongodb;
let uri = `mongodb://${dbConnectConfig.user}:${dbConnectConfig.password}#${dbConnectConfig.server}:${dbConnectConfig.port}/${dbConnectConfig.database}`;
console.log('uri:', uri);
mongoose.connect(uri);
mongoose.Promise = global.Promise;
let userModel = mongoose.model('pub_user', require('./db-schemas/pub/user'), 'pub_user');
let user = await userModel.findOne();
console.log('user:', user.name, user);
})();
console print
user: undefined { _id: 57c38b1573a1951a327b3485,
password_hash: 'fc76c4a86c56becc717a88f651264622',
type: 'A0001',
phone: '13623366688',
name: 'root',
code: 'root#local',
stop_flag: false,
system_flag: true,
roles: [ '4096' ],
status: 1,
operated_on: 2016-08-30T02:29:48.246Z,
check_in_time: 2016-08-29T01:08:37.327Z,
__v: 0 }
the problem is the user.name is undefined;
when I use callback
userModel.findOne().exec((err, user) => {
"use strict";
console.log('user:', user.name, user);
})
still use.name is undefined
the schema
import mongoose from 'mongoose';
import DICT_PUB from '../../pre-defined/dictionary-pub.json';
const PUB06 = DICT_PUB["PUB06"];
const userSchema = new mongoose.Schema({
check_in_time: {type: Date, default: Date.now},
operated_on: {type: Date, default: Date.now},
status: {type: Number, min: 0, max: 1, default: 1},
code: {type: String, required: true, maxlength: 30, index: {unique: true}},
name: {type: String, required: true, maxlength: 30},
phone: {type: String, maxlength: 20, unique: true, index: true},
type: {type: String, enum: Object.keys(PUB06).slice(1)},
roles: [String],
system_flag: {type: Boolean, default: false},
stop_flag: {type: Boolean, default: false},
password_hash: String,
tenantId: {type: mongoose.Schema.Types.ObjectId, required: true,ref:'pub_tenant'}
}, { strict: false });
userSchema.pre('update', function (next) {
this.update({}, {$set: {operated_on: new Date()}});
next();
});
userSchema.pre('save', function (next) {
console.log('password_hash:');
if (!this.password_hash) {
this.password_hash = ...
}
next();
});
export default userSchema;
solved
when es6 module export default , and need use
require('path').default
or
import schema from 'path';

How to take only articles by given user Express.js

I want to display in my user/myarticlesview only articles by logged in user.
How can i do that:
Here is my User model and Article schema:
let userSchema = mongoose.Schema(
{
email: {type: String, required: true, unique: true},
passwordHash: {type: String, required: true},
salt: {type: String, required: true},
articles: [{type: ObjectId, ref: 'Article'}],
roles: [{type: ObjectId, ref: 'Role'}]
}
);
let articleSchema = mongoose.Schema (
{
author: {type: ObjectId, ref: 'User'},
title: {type: String, required: true },
content: {type: String, required: true },
phone: {type: Number, required: true },
date: {type: Date, default: Date.now() }
}
);
I want to do this in my userController and passed it to the view:
myArticlesGet: (req, res) => {
if (!req.isAuthenticated()) {
res.redirect('/');
return;
}
res.render('user/myarticles')
}
I cant figure it out how to make the query.Thank you.
As you are using express sessions you can store userId in the express session when the user is authenticated and then you can get user articles from user like that
User.find({_id: req.session.userId}).populate('articles')

ActionHero js with Mongoose

I am creating some rest API with ActionHero js and Mongoose.
I put the Mongoose code in an initalizers and everything works.
When I modify some files the project automatically recompiles and it returns the following error: OverwriteModelError:
Cannot overwrite User model once compiled.
How should I edit my code to avoid this error?
'use strict';
var mongoose = require('mongoose');
exports.mongo = function(api, next) {
mongoose.connect(api.config.mongo.host);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
console.log('Connection opened');
});
var Schema = mongoose.Schema,
Types = mongoose.Schema.Types;
var userSchema = mongoose.Schema({
createdAt: { type: Date, default: Date.now(), required: true},
updatedAt: { type: Date, required: false},
email: { type: String, required: true },
name: { type: String, required: true },
surname: { type: String, required: true },
password: { type: String, required: true },
roles: [],
tokens: [{
code: String,
expiryDate: { type: Date, default: Date.now() + 30 }
}]
});
var User = mongoose.model('User', userSchema);
var postSchema = mongoose.Schema({
createdAt: { type: Date, default: Date.now(), required: true},
updatedAt: { type: Date, required: false},
content: { type: String, required: true },
votes: { type: [Types.ObjectId], ref: 'User' } ,
coordinates: { type: [Number], index: { type: '2dsphere' }, required: true },
creator: { type: Schema.Types.ObjectId, ref: 'User', required: true }
});
var Post = mongoose.model('Post', postSchema);
api.mongo = {
mongoose: mongoose,
user: User,
post: Post
};
next();
};
actionhero will reload any initializers if you are in developmentMode. You should wrap your connection steps within the _start() block, rather than have them run in-line each time. This way, actionhero can re-load the file and not re-run your connection steps.
http://actionherojs.com/docs/core/initializers.html

Resources