How to make some fields not updatable once saved in mongoose? - node.js

I have build a schema as follows:
const UserInfoSchema = new Schema({
email: { type: String, required: true, unique: true },
username: { type: String, required: true, unique: true },
userId: { type: Schema.Types.ObjectId, ref: 'User'},
displayName: { type: String, required: true },
profilePic: {
filename: {type: String},
url: {type: String}
},
created_at: Date,
updated_at: Date
})
What I need here is once the fields such as email, username and userId are saved, should not be modified. Is there anything pre-build in mongoose for this kind of feature?
I have done some research on schema.pre('update', (next) => {}), but got nothing really useful/don't know if one can use for the mentioned feature. Any help on this matter is greatly appreciated. Thanks in advance.

There is an easier way
when you save the Schema, you can set the field as immutable, like this
const UserInfoSchema = new Schema({
email: { type: String, required: true, unique: true, immutable:true },
username: { type: String, required: true, unique: true, immutable:true },
userId: { type: Schema.Types.ObjectId, ref: 'User', immutable:true},
displayName: { type: String, required: true },
profilePic: {
filename: {type: String},
url: {type: String}
},
created_at: Date,
updated_at: Date
})
it won't throw any error, if you want it you should check it elsewhere, but when you try to modify the immutable fields, it wont be changed at all

for(const key in userUpdates) {
switch(key) {
case 'username':
case 'email':
throw new Error('These field/s cannot be changed anymore');
}
}
User.findByIdAndUpdate(id, userUpdates, { new: true, runValidators: true });

Related

NodeJS - Mongoose Populate Nested Items

I am trying to populate a GET request.
This my model/schema:
const turnosSchema = mongoose.Schema({
turno: { type: Number, required: true},
nombre: { type: String, required: true},
hora_inicio: { type: String, required: true},
hora_fin: { type: String, required: true},
menus: { type: Array, required: true},
cod_vestir: { type: mongoose.Schema.Types.ObjectId, ref: 'cod_vestir', required: true},**//This is the item I want to populate with another collection called "codsvestirs"**
})
const LandingAyBSchema = mongoose.Schema({
titulo: { type: String, required: true},
especialidad: { type: String, required: true},
descripcion: { type: String, required: true},
observaciones: { type: String, required: true},
turnos: [turnosSchema],**//This is an array with a "turnosSchema"**
orden: { type: Number, required: true},
activo: { type: Number, required: true},
imagen: {type: String, required: true},
lang: { type: String, required: true, maxLength: 2},
})
Heres is a pic of the data hierarchy.
Here is the code I have so far. It doesn't have the actual populate code cause I have not been able to make it work. I've tried the solution from this thread which I think better suits my scenario but it didn't work Populate nested array in mongoose
exports.getAllLandingAyB = async (req, res, next) => {
const query_result = await LandingAyB.find({activo: 1}).sort({orden: 1});
if (!query_result) {
res.status(500).json({success: false})
}
res.status(200).json({
success: true,
cuantosLandings: query_result.length,
data: query_result
});
}
You need to set the type as a mongoId and then refer to the selected collection. For example on the turnos property
turnos: [{ type: Schema.Types.ObjectId, ref: 'Turnos' }]
I'm asumming the Turnos is the name of the collection, and the query shoud look like this
const query_result = await LandingAyB.find({activo: 1})
.populate('turnos')
.sort({orden: 1});.
you can find a good example on the populate documentation

Trouble with mongoDB Ref -> trying to ref array of diferent model

so i'm trying ref a array of daysOff (Ferias model) as a fiel in a User model,
i'm new to MongoDB and mongoose, and i'm trying to build a API that manages a company workers days off.
I apologyse in advance for the "format" of this question but it's the very first time that I post a question in StackOverflow :)
Thanks u all!
const mongoose = require("mongoose");
const moment = require("moment");
const feriasSchema = mongoose.Schema(
{
user: {
type: mongoose.Types.ObjectId,
required: true,
ref: "User",
},
firstName: {
type: String,
ref: "User",
},
lastName: {
type: String,
ref: "User",
},
workerNumber: {
type: Number,
ref: "User",
},
sectionOfWork: {
type: String,
ref: "User",
},
totalFerias: {
type: Number,
required: true,
},
//this is the field i want to add in User model as an array of (dates format DD/MM/YYYY)
ferias: {
type: [String],
//default: [Date],
required: true,
},
tipoFerias: {
type: String,
required: true,
},
modo: {
type: String,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("Ferias", feriasSchema);
// USER MODEL
const userSchema = mongoose.Schema(
{
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
email: {
type: String,
required: [true, "Please enter a valid email address"],
unique: true,
},
password: {
type: String,
required: [true, "Please enter a password"],
},
workerNumber: {
type: Number,
required: true,
unique: true,
},
sectionOfWork: {
type: String,
required: true,
},
chefia: {
type: String,
required: true,
},
//this is the field i want to be an array (from Ferias model)
ferias: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Ferias",
}],
role: {
type: String,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", userSchema);
what am i doing wrong?
i'm getting and empty array ...
in express I can send the questioned data separately but u want to send a json to some frontend with all the fields of a user, with the "ferias" array present.

I want to join two schemas into one schema in nodejs mongodb

I want to join two schemas into one because they both have almost same attributes and i want to use it for PostSchema that a user and also an owner can create and show their posts but i dont know how to achieve it
for example :
UserSchema
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
gender: String,
role: {
type: String,
default: "User",
},
});
OwnerSchema
const OwnerSchema = new mongoose.Schema({
name: String,
gender: String,
email: String,
password: String,
role: {
type: String,
default: 'Owner'
},
restaurant: RestaurantSchema
})
PostSchema
const PostSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
photo: {
type: String,
required: true,
},
postedBy: {
type: ObjectId,
ref: *Combined user and owner*,
},
comments: [CommentSchema],
}, { timestamps: true });
Get rid of your OwnerSchema - and modify your UserSchema to something like the below:
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
gender: String,
role: {
type: String,
default: "User", //could be Owner when applicable
},
restaurant: RestaurantSchema, //could be null when role=User
});

Mongoose schema with field of an array of other schemas

first of all, I am a beginner and currently, I am working on a social media blog type.
Now, I have my userSchema and postSchema models:
USER MODEL
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please insert your name'],
},
email: {
type: String,
required: [true, 'Please insert your email'],
unique: true,
lowercase: true, //transform into lowercase / not validator
validate: [validator.isEmail, 'Please provide a valid email'],
},
avatar: {
type: String,
},
role: {
type: String,
enum: ['user', 'admin'],
default: 'user',
},
password: {
type: String,
required: [true, 'Please provide a password'],
minLength: 8,
select: false,
},
passwordConfirm: {
type: String,
required: [true, 'Please confirm your password'],
validate: {
validator: function (el) {
return el === this.password;
},
message: 'Passwords are not the same',
},
},
passwordChangedAt: Date,
posts: [] // ???????????????
});
POST MODEL
const postSchema = new mongoose.Schema({
title: {
type: String,
required: [true, 'A post must have a title'],
},
author: {
type: String,
required: [true, 'A post must have a title'],
},
likes: {
type: Number,
default: 10,
},
comments: {
type: [String],
},
image: {
type: String,
},
postBody: {
type: String,
required: [true, 'A post must contain a body'],
},
createdAt: {
type: Date,
default: Date.now(),
select: false,
},
});
Now I don't know if it's the best approach but I was thinking of having a field in userSchema with the type of an array of postSchema so I will have for each user their own posts created. Can I do that? If not how I can achieve that?
Should I use search params fields to filter posts by the author? I am really confused how I should approach this situation. Thank you guys
Check out this example
const UserSchema = new mongoose.Schema({
username: String,
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}]
})
const PostSchema = new mongoose.Schema({
content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
})
const Post = mongoose.model('Post', PostSchema, 'posts');
const User = mongoose.model('User', UserSchema, 'users');
module.exports = { User, Post };
Credit: https://medium.com/#nicknauert/mongooses-model-populate-b844ae6d1ee7

Schema Association in Mongoose

I have 2 models:
Here is the User Model:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
passwordResetToken: String,
passwordResetExpires: Date,
facebook: String,
twitter: String,
tokens: Array,
profile: {
name: String,
gender: String,
location: String,
website: String,
picture: String
}
}, { timestamps: true });
And here is the Revive Model:
const reviveSchema = new mongoose.Schema({
reviveShowName: {type: String, required: true},
reviveTitle: {type: String, required: true},
reviveCategory: {type: String, required: true},
reviveGoal: {type: Number, required: true},
revivePhoto: {type: String, required: true},
reviveVideo: {type: String},
reviveStory: {type: String},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
name: String
}
}, { timestamps: true });
In the Revive model, I'm trying to the reference the author and get the author's id and that works... How do I also get the name from profiles -> name...? Clearly name: String is wrong...
Mongoose relations work, based on the ref and type value of the nested object. In your case you have associated the id property of author to point to the User model.
If you want to populate the author with the user information, you should just do :
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
Then in your query you just use populate
Revive.find({})
.populate( 'author' )
.exec( function( error, docs ) {
console.log( docs ); // will have `[{author:{profile:{...}}}]` data
} );

Resources