I'm studying Mongodb and I'm using Mongoose and I would like to create a very dynamic registration process. I managed the first step of the registration using Passport and everything works fine, I created the user and it is present on the DB. Now my registration process will continue and user have to select a "role": What kind of user you are? There are 2 options: "basic" and "advanced". Basic has just 3 properties and advanced has the 3 basic properties plus few others.
I need to extend the userSchema or to add new fields based on that role but after a week it doesn't work yet and I tried many NPM like: mongoose-relationship or mongoose-schema-extend.
This is basically what I have:
userSchema = new Schema({
id : Number,
email : { type: String, required: true },
role : { type: String, required: true },
profile : { ... } // Profile fields are different for each role.
});
// profile 1
basicSchema = new Schema({
info1 : { type: String, required: true },
info2 : { type: String, required: true },
info3 : { type: String, required: true }
});
// profile 2
advancedSchema = new Schema({
info1 : { type: String, required: true },
info2 : { type: String, required: true },
info3 : { type: String, required: true },
info4 : { type: String, required: true },
info5 : { type: String, required: true },
info6 : { type: String, required: true }
});
The user already exist and he is on a screen where he need to choose a role and populate the chosen profile.
For information I'm using nodejs and expressjs.
I hope you can help. Thanks.
Using mongoose-schema-extend:
Install via npm:$ npm install mongoose-schema-extend
Example using your code:
var mongoose = require('mongoose'),
extend = require('mongoose-schema-extend');
var Schema = mongoose.Schema;
var userSchema = new Schema({
id : Number,
email : { type: String, required: true },
role : { type: String, required: true },
},{ collection : 'users' });
//profile 1
var basicSchema = userSchema.extend({
info1 : { type: String, required: true },
info2 : { type: String, required: true },
info3 : { type: String, required: true }
});
//profile 2
var advancedSchema = userSchema.extend({
info1 : { type: String, required: true },
info2 : { type: String, required: true },
info3 : { type: String, required: true },
info4 : { type: String, required: true },
info5 : { type: String, required: true },
info6 : { type: String, required: true }
});
mongoose-schema-extend
This is what you want. The concept of "inheritance" and discriminatory field. Give it a shot. I used it and works wonders. Basically you have 3 types of users: basic, advanced and expert. Each is based on your core/base model and then you extend with extra properties you need, defining one inheritance per role.
This gives you a lot of advantages, mainly: mongoose will populate the appropriate model and kick any validation you have in the derived models, etc.
https://github.com/briankircho/mongoose-schema-extend
Related
I'm very new to Data base design
I'm going to design MongoDB data base for a weblog .
every post of blog will have comments .
now , we can design database in two approaches
Ffirst Approach
const postSchema = new mongoose.Schema(
{
title: {
required: true,
type: String
},
body: {
required: true,
type: String
},
comments: [{
required: true,
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment'
}],
}
)
const commentSchema = new mongoose.Schema(
{
text: {
required: true,
type: String
}
}
)
As you see Coments in post model is Array of Comments
Second Approach
const postSchema = new mongoose.Schema(
{
title: {
required: true,
type: String
},
body: {
required: true,
type: String
},
}
)
const commentSchema = new mongoose.Schema(
{
text: {
required: true,
type: String
},
post_id: {
required: true,
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
},
}
)
As you can see ,there is user_id in comment schema .
the question is that
which schema model is correct ?
what are pros and cons of each schema ?
My website is running allright and it's connected with Database.
I had to add more informations in my Mongo's collection. (I created the ActionPlanSchema).
import mongoose from "mongoose";
import mongoose_delete from "mongoose-delete";
const VerificationSchema = new mongoose.Schema({
text: { type: String, required: true },
});
const ActionPlanSchema = new mongoose.Schema({
title: { type: String, required: true },
mouraTitle: { type: String, required: true },
text: { type: String, required: true },
});
const RequirementSchema = new mongoose.Schema({
itemNumber: { type: String, required: true },
normPart: {
type: mongoose.Schema.Types.ObjectId,
ref: "NormPart",
required: true,
},
generalRequirement: {
type: mongoose.Schema.Types.ObjectId,
ref: "GeneralRequirement",
required: true,
},
specificRequirementDescription: { type: String, required: true },
subject: { type: mongoose.Schema.Types.ObjectId, ref: "Subject" },
criterion: String,
verification: [VerificationSchema],
actionPlan: [ActionPlanSchema],
});
RequirementSchema.index({ itemNumber: 1, normPart: 1 });
RequirementSchema.index({ specificRequirementDescription: 1 });
RequirementSchema.plugin(mongoose_delete, {
overrideMethods: "all",
deletedAt: true,
deletedBy: true,
indexFields: ["deleted"],
});
export default RequirementSchema;
And using a router in Postman (PUT method), I added some information to the Database ActionPlanSchema. Looking like that:
In my localhost, the actionPlan information it's showing. But when I do the deploy, the actionPlan gets undefined.
I believe that it's because the informations that I added in Postman weren't sent to the database used on the Deploy App.
How can I solve this problem? (I don't know if I could be very clear about my issue)
Anyway, thanks so much!
I was working on a project where we can create a form like google forms and get responses from users, and then we can view those responses in the admin panel.
My English is not that good I tried my best to explain the problem!
I am using MERN Stack so I was tucked into a problem related to how to save the questions and record the responses in MongoDB in a standard way in objects and arrays.
currently I added this as a form model :
const formSchema = new Schema({
usererId: { type: Schema.Types.ObjectId, ref: 'User' },
title: { type: String, required: true },
description: { type: String},
username: { type: String, required: true },
password: { type: String, required: true },
isEnabled: { type: Boolean, default: true },
expiresOn: { type: Date, default: null },
fields: [
{
title: { type: String, required: true },
placeholder: { type: String, required: false },
type: { type: String, required: true },
required: { type: Boolean, required: true },
options: [
{
title: { type: Object, required: true },
priority: { type: Number, default: 0, required: true }
}
],
priority: { type: Number, required: true, default: 0 },
enabled: { type: Boolean, default: true, required: true }
}
],
}, {
timestamps: true
})
and form responses :
const formResponseSchema = new Schema({
digitalFormId: { type: Schema.Types.ObjectId, ref: 'Form' },
isVerified: { type: Boolean, default: false },
formResponse: [{ type: Object, required: true }],
}, {
timestamps: true
})
I don't know if this approach is good, I myself like it's not like a standard one and I m confused, Someone please tell me how should I do it and what is the perfect way of doing it,
If you have a problem understanding what I am saying just tell me simply how a google form works in the backend from API view, like question ID server-side validation and response submit, that time what type of request is sent to the server, something like this !
If you don't mind please take out some time and write a brief approach of what type of Schema should I use and how should I save them.
Something more important is what approach to use while checking the form response data coming from the client to validate on server-side means on express API, like {questionId: idofquestion, value:'Value of the response of the particular question'}, later checking the question label and all other things with the form questions and all validation rules to fetch from them and check, but I don't know how to do that It's really confusing for me.
Thanks in Advance for the help! ❤️
I have a user model here that currently only have 2 possible roles. One is admin and one is regular user.
const userSchema = mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
isAdmin: {
type: Boolean,
required: true,
default: false
}
}, { timestamps: true
})
As you can see, if the isAdmin was set to true, it will automatically become an admin otherwise its a regular user.
But things change when I added a new role like: isOwner which is I added a new field again:
const userSchema = mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
isAdmin: {
type: Boolean,
required: true,
default: false
},
isOwner: {
type: Boolean,
required: true,
default: false
},, { timestamps: true
})
As you can see I added a new field isOwner at the top.
My question is given these three roles: isAdmin, isOwner and regular user, am I doing the right way to do this and manage 3 different roles? or is there a better way to do this?
Note: The way this works is that admin has the overall access to all of the job post of the owner while the regular user can only comment on the job post posted by the owner (who posted the job)
In future you may have more roles, It is best to use Array field for user roles.
array reference document
const userSchema = mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
isAdmin: {
type: Boolean,
required: true,
default: false
},
roles: {
type:[String],
required: true,
default:["regular"]
}
},
{ timestamps: true
})
I'm using MongoDB, and express.
I have a collection with all the countries, contains the states and cities.
Picture of a part of the collection
Now,
lets say I want to get all the cities that contains "Los" (like "San Antonio", "San Diego"),
when I'm using Find() - its return the all document with all the states and all the cities in the country (like in the picture above),
I want to return the all documents, but return only the objects that contains the value, inside array "cities"
Note: I expect to get different countries with cities that contains a part of the value in their names.
how to use the Find() to return as I want ?
hers is the schema I'm using:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CitiesSchema = new Schema({
capital:{
type: String,
required: true
},
currency:{
type: String,
required: true
},
emoji: {
type: String,
required: true
},
emojiU: {
type: String,
required: true
},
id: {
type: Number,
required: true
},
iso2: {
type: String,
required: true
},
iso3: {
type: String,
required: true
},
name: {
type: String,
required: true
},
native: {
type: String,
required: true
},
phone_code: {
type: String,
required: true
},
region: {
type: String,
required: true
},
states:
[{
cities:[{
id:{
type: Number,
required: true
},
latitude:{
type: String,
required: true
},
longitude:{
type: String,
required: true
},
name:{
type: String,
required: true
},
}],
id:{
type: Number,
required: true
},
name:{
type: String,
required: true
},
state_code:{
type: String,
required: true
},
}]
,
subregion: {
type: String,
required: true
}
});
const Cities = mongoose.model('Cities',CitiesSchema);
module.exports = Cities;
Edit: my Find() code:
Cities.find({"states.cities.name": city})
.then((data)=>{
return res.json(data);
})
lets say I want to search cities with the name "Los Santos". I want the result to be like this:
Picture of the result I expect to be return
instead, I'm getting the all states and cities in the countries - which I don't want.
UPDATE:
I found a way to return the data as I wish, by using aggregate with $unwind.
Cities.aggregate([{
$unwind: '$states'
},
{
$unwind: '$states.cities'
},
{
$match: {
'states.cities.name': {$regex: city, $options: "i"}
}
}
],
function (error, data) {
return res.json(data);
})
Try using RegEx, I use it while doing searches on MongoDB.
Cities.find({"states.cities.name": new RegExp(city)})
.then((data)=>{
return res.json(data);
})
I found a way to return the data as I wish, by using aggregate with $unwind.
Cities.aggregate([{
$unwind: '$states'
},
{
$unwind: '$states.cities'
},
{
$match: {
'states.cities.name': {$regex: city, $options: "i"}
}
}
],
function (error, data) {
return res.json(data);
})