Mapping Many To Many Relationship in Mongodb, Also considering scaling - database

I have a jobs collection which is like this
const JobSchema = new Schema({
jobCode: String,
companyName: String,
jobDesignation: {
type: String,
required: [true, "Please Provide Job Designation"],
},
jobVacancy: {
type: Number,
required: [true, "Please Provide Job Vacancy"],
},
postedOn: {
type: Date,
default: Date.now(),
},
})
and a users collection,
const UserSchema = new Schema(
{
firstName: {
type: String,
required: [true, "Please Provide First Name"],
},
lastName: {
type: String,
required: [true, "Please Provide Last Name"],
},
To map a many to many relationship b/w users and jobs collection where each user is able to apply to many jobs and each job can have many users, while designing the schema and considering we have to scale we cannot embed the ids in either collection because of the 16MB limit of a document, So is it better to create a third collection and have user and jobs id in it as references?
Like This
const UserJobSchema = new Schema({
job:{
type: mongoose.Schema.ObjectId,
ref: "JobSchema",
},
user:{
type: mongoose.Schema.ObjectId,
ref: "UserSchema",
},
})

Related

Why is my mongoose populate query throwing "Cannot populate path because it is not in your schema" error?

I'm building a form management program but right now I'm just trying to build a queue system to handle all the forms when they're assigned to someone.
when I call this first function, it should populate the elements of the activeWork array by pulling from each collection that the entries reference, there are several collections that could be referenced in active work, so I'm trying to use the collection type field to determine what collection to pull from, I don't know if I formatted any of this correctly because its my first time building any of this.
import statesPersons from "./statesPersons.schema.js";
export async function getStatesPersonsActiveWorkByProfileId(req, res){
try{
const { profileId } = req.params
const data = await statesPersons.find({profileId})
.populate('statesPersons.activeWork.referenceId')
return res.send({
message: "success",
data: data,
status: 200 })
}catch(e) {
console.error(e.message)
return res.send({
message: "couldn't fetch active work",
data: null,
status: 500 })
}
}
Here is the schema for statesPersons, the collection where active work is stored.
import mongoose, {model, Schema} from "mongoose";
const activeWorkSchema = new Schema({
active: Boolean,
collectionType: {
type: String,
enum: ['messages'],
},
referenceId: {
type: Schema.Types.ObjectId,
refPath: "statesPersons.activeWork.collectionType"
},
sentBy: {
type: Schema.Types.String,
ref: "statesPerson",
},
sentTo: {
type: Schema.Types.String,
ref: "statesPerson",
},
timeRecived: Date,
dueDate: Date,
subject: String,
viewed: Boolean,
content: {},
})
const statesPersonsSchema = new Schema({
profileId:{
type: String,
required: true,
unique: true
},
department: {
type: String,
required: true,
index: true,
},
firstName: String,
lastName: String,
location: String,
org: String,
title: String,
jobDescription: String,
email: {
type: String,
lowercase: true,
},
phoneNumber: String,
activeWork: [activeWorkSchema],
emailList: [String],
jobAssignments: [String],
affiantInfo: {
affiantInfoTitle: String,
affiantInfoExperience: String,
},
assessments: [
{
assessdBy: {
type: Schema.Types.ObjectId,
ref: "statesPerson",
},
dueDate: Date,
questions: {},
},
],
});
export default mongoose.model("statesPersons", statesPersonsSchema);
When I make a query, I get:
Cannot populate path statesPersons.activeWork.referenceId because it is not in your schema. Set the strictPopulate option to false to override.
I don't know if I formatted my populate correctly or if the problem is in my schema,

Advice for MongoDB schema design for social media post

I have been using MongoDB for my application but would like to add a social media post feature into the system. However, given the requirements, I find that it is not easy to come up with a MongoDB schema that would be effective for my use case. Any expert here care to share their suggestions?
The requirements are:
User can post social media post (imagine instagram posts)
User will view social media posts by other users
When a post is on a user screen for 5 second, we will record that the user has seen the post
Post that are seen will be appears in the user's social media feed
Any help would be appreciated, thank you!
You can refer below schema which we require to manage users and their post along with post history like ( who liked, who watched and who add comments)
// Users schema
const userSchema = new Schema({
name: {
type: String,
trim: true
}
});
// Post related media schema
const postMediaSchema = new Schema({
url: {
type: String,
trim: true
}
}, {
_id: false
})
// Post schema
const postSchema = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref:'users',
},
title: {
type: String,
trim: true
},
description: {
type: String,
trim: true
},
media: [postMediaSchema],
tags: [String]
});
// Users and posts relation schema
const postWatchHistory = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref:'users',
},
postId: {
type: Schema.Types.ObjectId,
ref:'posts',
},
});
// Post liked history schema
const postLikedHistory = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref:'users',
},
postId: {
type: Schema.Types.ObjectId,
ref:'posts',
},
});
// Post comment history schema
const postCommentHistory = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref:'users',
},
postId: {
type: Schema.Types.ObjectId,
ref:'posts',
},
text:{
type: String,
required: true,
trim: true
},
status:{
type: String,
enum:['Y', 'N'],
default:'N',
trim: true
}
});

how to make a dynamic form creation and response mangement system like google forms work?

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! ❤️

mongodb User with subdocument vs document with UserId

I am using meanjs and I would like to store some user data in a one to many relationship. My case is similar to the articles example but the articles will only ever be accessed through the user. I want the route to be something like
Users/:userId/articles
or
Users/me/articles
Question 1
Should I just stick with the articles model as it is or should I make articles a subdocument of user. e.g.
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\#.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: 'testing error message',
required: 'Please fill in a username',
trim: true
},
articles: [articleModel.schema],
password: {
type: String,
default: '',
validate: [validateLocalStrategyPassword, 'Password should be longer']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'store', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
},
/* For reset password */
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
Question 2 if I make it a subdocument can I still use the $resource function or do I have to make custom functions?
The maximum BSON document size is 16 megabytes. The maximum document size helps ensure that a single document cannot use excessive amount of RAM or, during transmission, excessive amount of bandwidth. To store documents larger than the maximum size, MongoDB provides the GridFS API.

Mongoose relationship

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

Resources