mongoose document can't access property and can't save - node.js

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';

Related

Cannot Populate path in Mongoose while trying to join two documents

MongooseError: Cannot populate path loaned_to because it is not in your schema. Set the strictPopulate option to false to override.
I've tried to join two documents in mongodb using mongoose in nodejs, But unfortunately this error occurs. My mongoose version is 6.0.6
Book Schema
const mongoose = require('mongoose');
const BookSchema = new mongoose.Schema({
"name": {type: String, required: true},
"author_name": {type: String, required: true},
"published_date": {type: Date, required: false},
"copies": [
{
"isbn_number": {type: String, required: true},
"status": {type: String, required: true, default: "Available"},
"due_back": {type: Date, required: false},
"loaned_to": {type: mongoose.Schema.Types.ObjectId, required: false, ref: "User"}
},
]
})
const Book = mongoose.model("Book", BookSchema);
module.exports = Book;
User Schema
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
"first_name": {type: String, required: true},
"last_name": {type: String, required: true},
"phone_number": {type: String, required: true},
"address": {type: String, required: false},
"user_name":{type: String, required: true},
"password": {type: String, required: true},
"email": {type: String, required: true},
"notifications": [
{
"notification_id" : {type:"string", required:true},
"notification": {type: "string", required: true}
},
]
})
const User = mongoose.model("User", UserSchema);
module.exports = User;
My code to join documents
exports.getAllBooks = async (req, res) => {
try {
let data = await BookModel.findOne().populate("loaned_to");
res.status(200).send({data: [...data], success: true})
} catch (err) {
console.log(err)
res.status(404).send({success: false, msg: err.message})
}
}
exports.getAllBooks = async (req, res) => {
try {
let data = await BookModel.findOne().populate({
path: 'copies.loaned_to',
select:
'first_name lastName phone_number address user_name email notifications',
});
res.status(200).json({ data: [...data], success: true });
} catch (err) {
console.log(err);
res.status(500).json({ success: false, msg: err.message });
}
};
Use nested populate as in the example below(The example assumes that a Token model has a user which in tern has a role and a role has permissions).
This will return a user object associated with the filtered token, with the role the user is assigned to and the permissions assigned to the role.
That is: TokenModel (has relationship to) -> UserModel (has relationship to) -> RoleModel (has relationship to) -> PermissionsModel)
const popObj = {
path: 'user',
options: { sort: { position: -1 } },
populate: {
path: 'role',
select: 'name',
populate: {
path: 'permissions'
}
}
};
const tokenFilter = {is_active: true};
TokenModel.find(userFilter).populate(popObj);

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...

How does module.exports work

I'm using Express and Mongodb to write my first web app and this is probably a noob question, but let's say I were to define a user model in a file called users.js and then called const User = module.exports = mongoose.model('User', UserSchema) somewhere in the file.
Upon importing users.js (via const User = require([path to users.js]) to some other file in the app, why can I then call new User and have access to the model instead of having to call new users.User?
The standard way to define the model and using the schema in the controller
User.js
//User Model
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
id: String,
name: {
type: String,
index: true
},
email: {
type: String,
trim: true,
index: true,
lowercase: true,
unique: true
},
mobile: {
type: String,
trim: true,
index: true,
unique: true,
required: true
},
profilePic: String,
password: { type: String },
locations: [{}],
location: {
type: { type: String, default: 'Point', enum: ['Point'] },
coordinates: { type: [], default: [0, 0] },
name: String,
shortAddress: String
},
address: String,
gender: String,
dob: Date,
signupType: { type: String, enum: ['facebook', 'google'] },
deviceType: String,
createdTime: Date,
updatedTime: Date,
googleToken: String,
facebookToken: String,
fcmToken: String,
facebookLink: String,
facebookId: String,
memberType: String,
deviceId: String,
preferences: [{}],
loginData: [{}],
token:String,
isVerified: Boolean,
isMobileVerified: Boolean,
isEmailVerified: Boolean,
lastSeen: Date
});
// 2D sphere index for user location
userSchema.index({ location: '2dsphere' });
mongoose.model('User', userSchema);
module.exports = mongoose.model('User');
UserController.js
//User Controller
var User = require('./User');
// RETURNS ALL THE USERS IN THE DATABASE
router.get('/', function (req, res) {
User.find({}, function (err, users) {
if (err) return res.status(500).send({ errors: "There was a problem finding the users." });
res.status(200).send(users);
});
});

Mongoose Populate Not Working For Me

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

Mongoose: Populating with projection using attribute of scheme

I triying the following population/projection and work fine
modelBaby.findOne({'userId': req.user.data._id, '_id': req.params.id})
.populate('categories._categoryId', {
levels:{
$elemMatch:{
name: 'PURPLE'
}
}
})
But i need name as a variable something like:
modelBaby.findOne({'userId': req.user.data._id, '_id': req.params.id})
.populate('categories._categoryId', {
levels:{
$elemMatch:{
// over heree !!
name: 'categories._levelName' or this._levelName
}
}
})
the scheme ref is
const babyCategory = new mongoose.Schema(
{
answer: {type: String},
_categoryId: {type: Schema.Types.ObjectId, required: true, ref: 'category'},
_categoryName: {type: String, required: true},
_levelName: {type: String, required: true}
},
{versionKey: false, _id : false}
);

Resources