mongoose schema contains entire DB object instead of defined schema object - node.js

I'm using two schemas for users. One that contains the password/salt, one that doesn't for returning to the front end. When I use the model that uses the schema WITHOUT the password, it still returns the password :/
Generic User (For sending to the client)
module.exports = {
username: String,
email: String,
firstName: String,
lastName: String,
createdOn: Date,
updatedOn: Date,
scopes: [String]
}
Auth User (for creating/updating/authenticating users)
module.exports = {
username: String,
email: String,
password: String,
salt: String,
firstName: String,
lastName: String,
createdOn: Date,
updatedOn: Date,
scopes: [String]
}
Creating the models with
var modelInstance = mongoose.model("authUser", authUserSchema, 'users')
(in a different file)
var modelInstance = mongoose.model("user", userSchema, 'users')
modelInstance is exported with
module.exports = modelInstance;
Update This question answers mine.
How to protect the password field in Mongoose/MongoDB so it won't return in a query when I populate collections?

You don't have a clear question, but I guess you are asking if you can restrict it. The answer is 'no' by default.
There is a plugin for this: https://www.npmjs.com/package/mongoose-strictmodel
But it's really out of date.
It's easy enough though to create a wrapper function:
function safeUser(userModel) {
return {
username: userModel.username,
email: userModel.email,
firstName: userModel.firstName,
lastName: userModel.lastName,
createdOn: userModel.createdOn,
updatedOn: userModel.updatedOn,
scopes: userModel.scopes
}
}

Related

Creating different types of users in mongodb

I want to create an API to register, login and other things. two types of users
A teacher and a student , I'm using MongoDb and defining the schema.
const UserSchema = new Schema({
studentInfo : {
name: String,
email: String,
password: String,
birthday: Date,
state: String,
zip_code: String,
address: String,
phone_number: String,
},
teacherInfo : {
name: String,
email: String,
password: String,
birthday: Date,
state: String,
zip_code: String,
address: String,
phone_number: String,
course: {
title: String,
price: Number,
description: String
}
},
role: String
});
is this a good approach? or there is a better way?
I added the role field to perform route guarding on the front end.
I'm using Nodejs and Express.
any help will be much appreciated, thank you.
This is one way of embedding both student and teacher object in the same document and you can simply get data with single query. Although you don't need to separately embed the common fields in object like name, email, password, phone_number etc. teacherInfo would be like this
teacherInfo : {
course: {
title: String,
price: Number,
description: String
}
}
You can create different schemas for student and teacher (as they are unique and you might need them independent sometimes), and make User as the base model.
var User= new Schema({
name: String,
email: String,
password:String,
birthday: Date,
state: String,
zip_code: String,
address: String,
phone_number: String,
_teacher:{type:Schema.Types.ObjectId, ref:'Teacher'},
_student: {type:Schema.Types.ObjectId, ref:'Student'}
});
If _teacher has a value then the user can be considered as a teacher.
If _student has a value then the user can be considered as a student.
//Teacher Model
var Teacher = new Schema({
course: {
title: String,
price: Number,
description: String
},
//other teacher's fields
})
//Student Schema
var Student= new Schema({
//student's fields if you need in future
})

Trouble with object selection in Mongoose schema

Currently building an app whereby the user can log in either locally or via google (will be expanded to other social sites). I'm using an enum array to hold the possible login methods. My user schema looks as follows:
const userSchema = new Schema({
method :{
type: String,
enum: ['local', 'google', 'twitter'],
required: true
},
local: {
email: String,
username: String,
password: String,
projects: [
{
projectName: String,
sessionLength: Number,
timestamp: Date
}
]
},
google: {
googleId: String,
email: String,
username: String,
projects: [
{
projectName: String,
sessionLength: Number,
timestamp: Date
}
]
}
});
const User = mongoose.model('user', userSchema);
module.exports = User;
The following code is used to create the new user and save to the database after authentication by Google.
let newUser = new User({
method: 'google',
google: {
googleId: profile.id,
email: profile.emails[0].value,
username: profile.name.givenName
}
});
My problem is that newUser contains, as well as the correct google object, a 'local' object with a projects array. Below is how the newUser looks. I dont want it to include the local object. It also only seems to only appear if the projects property is an array, works as expected when projects is set to be a string. What am I doing wrong?
{ method: 'google',
_id: 5a32aaa4c665b062df9c0d00,
google:
{ googleId: 'randomgoogleId',
email: 'name#gmail.com',
username: 'name',
projects: [] },
local: { projects: [] } }

Mongoose Ref User Object

I hope everyone learning something today. I need some help. I have a Gift model which looks something like this:
let giftSchema = new mongoose.Schema({
gift: String,
date: {
type: Date
},
giftDescription: String,
giftAmount: String,
giftCode: String,
redeemCode: String,
passCode: String,
senderFirstName: String,
senderLastName: String,
giftMessage: String,
user: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
username: String
}
});
module.exports = mongoose.model('Gift', giftSchema);
This is my user model:
const mongoose = require('mongoose'),
passportLocalMongoose = require('passport-local-mongoose');
let UserSchema = new mongoose.Schema({
firstName: String,
lastName: String,
alaisFirstName: String,
alaisLastName: String,
username: String,
password: String,
isAdmin: Boolean,
addressLine1: String,
addressLine2: String,
city: String,
state: String,
zipCode: String
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
I have pretty much 2 users, and no guest. The admin sends gifts to a user. So as an admin, on the new route, I need to send something to the user. However, in my field: for ( think gmail search field ) I will be searching for either firstName, lastName, alaisFirstName, and alaisLastName than sending the gift to the user.
How could I model that? I cant do it by type: mongoose.Schema.Types.ObjectId, because the admin is the one sending it to the user, but I want something similar to that.

MongoDB trouble, is both way references a thing?

So I have a website built with node.js + mongoDB (mongoose). I'm having a bit trouble in the design of the database.
I want to have 2 logins, one for institutions and another for professionals. Do I need to double reference them (like the professional has a ref to Inst and an institution has a ref to the professional)?
For instance, If I want to display the list of all professionals when I login with an institution is trivial but if I don't ref the institution on the User (professional) is not so simple. So which one is better? Having code to find the user in every institution and get its institution name or both referencing each other and then do a populate?
If I pick both referencing each other, is there some way to guarantee that both of them will always be linked and having no broken only one way references?
Code:
var userSchema = new mongoose.Schema({
username: String,
password: String,
email: String,
name: String,
created_at: {type: Date, default: Date.now},
status : Boolean,
institution: { type:mongoose.Schema.ObjectId, ref:'Inst' }
});
mongoose.model('User', userSchema);
var User = mongoose.model('User');
var instSchema = new mongoose.Schema(
{
name : String,
professional : [{ type:mongoose.Schema.ObjectId, ref:'User'}]
});
mongoose.model('Inst', instSchema);
var Inst = mongoose.model('Inst');
How about just merge instSchema into userSchema as below, with additional user_type to indicate which type this user belong to, Professional or Institutions. Also one new related_user to store the other related User documents
var userSchema = new mongoose.Schema({
username: String,
password: String,
email: String,
name: String,
created_at: {type: Date, default: Date.now},
status : Boolean,
user_type: {type: String, enum: ['Prof', 'Inst']},
related_user: [{ type:mongoose.Schema.ObjectId, ref:'User'}]
});
mongoose.model('User', userSchema);
var User = mongoose.model('User');

Mongoose - Redefining schema structure

I have the following code:
var Schema = mongoose.Schema;
var personSchema = new Schema({
firstname: String,
lastname: String,
address: String,
});
var Person = mongoose.model('humans', personSchema);
var john = Person({ //will turn into a new object.
firstname: "john",
lastname: "doe",
address: "somewhere",
});
//save the user
john.save(function(err){
if(err) throw err;
console.log('person saved!');
});
now, in my database, I have a collection called humans with
firstname: "john",
lastname: "doe",
address: "somewhere",
as you can see above. My question is: is there a way that inside the humans collection, there will be 1 document that will have the structure you see above, and one with some new fields:
firstname: String,
lastname: String,
address: String,
car: String,
office: String
I have tried a couple of ways to redefine the structure of the personSchema
but it's always giving me the same error, Cannot overwrite model once compiled.”
Thank you for your time.
The error is occurring because you already have a schema defined, and then you are defining the schema again. Instantiate the schema once and the make Global object to access schema.
Change your Person schema, and add new fields
var personSchema = new Schema({
firstname: String,
lastname: String,
address: String,
car: String,
office: String
});
Documents which does not contain added fields after populating will have this keys but with undefined values.
For not ignoring new properties you can unstrict schema
var personSchema = new Schema({
firstname: String,
lastname: String,
address: String,
car: String,
office: String
}, {strict: false});
Also you can use Mixed type to set anything to property
var personSchema = new Schema({
firstname: String,
lastname: String,
additional: Mixed
});
And set other properties in additional field.

Resources