mongodb User with subdocument vs document with UserId - angularjs

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.

Related

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 - 3 types of roles

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
})

Get only the length of mongoose virtual populate

I would like to know if there is a way in Mongoose of getting the number of matching localField/foreignField as virtual field, without retrieving all the documents through virtual population.
Example:
const ForumThreadSchema = new Schema({
code: { type: Number, required: true, unique: true },
title: { type: String, min: [10, 'Too short title'], max: [200, 'Too long title'], required: true },
description: { type: String, min: [10, 'Too short description'], max: [2000, 'Too long description'], required: true },
creation_date: { type: Date, default: Date.now, required: true },
updated_date: { type: Date, default: Date.now, required: true },
_authorId: { type: Schema.ObjectId, ref: 'User', required: true },
_forumId: { type: Schema.ObjectId, ref: 'Forum', required: true }
}, {
collection: 'ForumThreads',
toObject: { virtuals: true },
toJSON: { virtuals: true }
});
const ForumMessageSchema = new Schema({
code: { type: Number, required: true, unique: true },
content: { type: String, min: [10, 'Too short message content'], max: [2000, 'Too long message content'], required: true },
creation_date: { type: Date, default: Date.now, required: true },
update_date: { type: Date, default: Date.now, required: true },
_authorId: { type: Schema.ObjectId, ref: 'User', required: true },
_forumThreadId: { type: Schema.ObjectId, ref: 'ForumThread', required: true },
_parentMessageId: { type: Schema.ObjectId, ref: 'ForumMessage' }
}, {
collection: 'ForumMessages'
});
The virtual populate on the forum thread schema retrieves me all the message documents. I need a virtual field with only their number if possible.
ForumThreadSchema
.virtual('messages', {
ref: 'ForumMessage',
localField: '_id',
foreignField: '_forumThreadId'
});
ForumThreadSchema
.virtual('messages_count')
.get(function() {
return this.messages.length;
});
The second virtual only works if the population of the first one is done.
I also want to mantain the virtual populate but I would like to find a way of getting the number of matching documents without use it (in server APIs that not need all message documents but only their size).
Is it possible?
You just need to add the count option:
ForumThreadSchema
.virtual('messages_count', {
ref: 'ForumMessage',
localField: '_id',
foreignField: '_forumThreadId',
count: true
});
And then when you can populate just the count:
ForumThread.find({}).populate('messages_count')
Doc: https://mongoosejs.com/docs/populate.html#count

Is it possible to only populate certain fields MongoDB

I'm using the following model schema:
var AppointmentSchema = new Schema({
appointment_date: {type: Date},
created: {
type: Date,
default: Date.now
},
updated: {type: Date},
client: [{ type: Schema.Types.ObjectId, ref: 'User' }],
staff_id: [{ type: Schema.Types.ObjectId, ref: 'User' }],
cost:{
type: Number
},
jobDone:{
type: Boolean,
default: false
},
cancelled:{
type: Boolean,
default: false
}
});
Which clearly references the User model.
When I query I want to populate the client and staff data, but without some of the fields that they hold within that model.
So if the Users model is:
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
}
});
I would only want to populate with firstName and email (and omit the rest) is that possible?
To return a few specific fields returned for the populated documents, you need to pass the usual field name syntax as the second argument to the populate method:
Appointment
.findOne({ cancelled: true })
.populate('client', 'firstName displayName') // only return the User's firstName and displayName
.exec(function (err, appointment) {
if (err) return handleError(err);
console.log('The client name is %s', appointment.client.firstName);
// prints "The client name is Aaron"
console.log('The client display name is %s', appointment.client.displayName);
// prints "The client display name is aarontest'
})

Bad request in MEAN stack app trying to append to an array in a schema

I am trying to pass an array of interest rates to a mongoose schema consisting of accounts.
I want to store interest rates that change at certain dates.
However, when I trigger the create function my dev tools tell me I have done something bad:
**400 Bad Request**
I have been using this as a template.
The view: has been disconnected so that I only pass:
var interest = {
rate: 1,
date: Date.now()
};
The controller that does the updating:
// Create new Account
$scope.create = function() {
// Create new Account object
var account = new Accounts ({
name: this.name,
desc: this.desc,
interests: []
});
// PROBLEMATIC PART
// Store interest:
var interest = {
rate: 1,
date: Date.now()
};
account.interests.push(interest);
// PROBLEMATIC PART END
// Redirect after save
account.$save(function(response) {
$location.path('accounts/' + response._id);
// Clear form fields
$scope.name = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
The mongoose schema:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
*
* Interest Rate Schema
*/
var InterestRate = new Schema({
rate:{
type: Number,
default: 0,
trim: true
},
date:{
type : Date,
default: '',
required: 'When is the interest to be updated',
trim: true
}
});
/**
* Account Schema
*/
var AccountSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Account name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
interests:
[{ type : Schema.Types.ObjectId, ref: 'InterestRate' }],
amount:{
type: Number,
default:0,
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Account', AccountSchema);
you can try by leaving the interest rate as a frond end structure and not define it in the model, then in the account schema set interests as type of [] and just push the objects
var AccountSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Account name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
interests:
type:[],
default:[]
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
just like this

Resources