Nodejs app with mongo database tables schema - javascript

I want to do a big project API where people can login with Google, send the token and when logged in do some actions saved to Mongo DB.
The problem is the tables structure, or schema. So, I want to do a good app scalable.
I have some tables like Users (with users loggin information) and I want user save his tasks, memories, works and more for him self, and when logged in in another device, get this information and modify.
Do I need to do every table for every user or use same table filtered by user?
For example, I have now this model for product:
const ProductoSchema = Schema({
nameOfProduct: {
type: String,
require: [ true, 'Required name' ],
unique: true
},
state: {
type: Boolean,
default: true,
required: true
},
userOwner: {
type: Schema.Types.ObjectId,
ref: 'Usuario',
required: true
},
priece: {
type: Number,
default: 0
},
category: {
type: Schema.Types.ObjectId,
ref: 'Category',
required: true
},
description: {
type: String
},
disponibility: {
type: Boolean,
default: true
},
img: {
type: String
},
});
Is this correct or this is not scalabe and I need to do all tables for every user?

Related

Mongoose: Populate or reference Id on Schema?

I am wondering which is better in terms of performance.
Let's say i have this Menu Schema
{
restaurant: { type: String, unique: true, required: true },
color: { type: String, required: true },
}
And i have this Plate Schema
{
name: { type: String, unique: true, required: true },
}
If i want to get all the plates from the Menu, which option is better?
Associate the Menu with plates like this:
{
restaurant: { type: String, unique: true, required: true },
color: { type: String, required: true },
plates: [
type: Schema.Types.ObjectId,
ref: 'plate'
]
}
Or like this:
{
name: { type: String, unique: true, required: true },
menu: {
type: Schema.Types.ObjectId,
ref: 'plate'
}
}
With the first option, i would use Menu.findById(id).populate('plates') to get the menu and all the plates associted with it. But with the second option, i would use Plate.find({menu: menu_id})
So, which is faster considering that i could have any amount of plates?
And if they are the same, is there a better way of associate Plate and Menu and get plates from Menu?
In terms of the performance, the second one would be faster because the first one would do the $lookup behind the scene (when doing populate), which is actually additional database call.
I would suggest the third option, which would be the best in your use case. That is embedding the plate documents inside the menu document.
{
restaurant: { type: String, unique: true, required: true },
color: { type: String, required: true },
plates: [
{
name: { type: String }
}
]
}
This way, menu document will contain all the information you needed and you can fetch everything with one database call.
Note: There is a limitation of 16MB for each document in the MongoDB. You can for sure store thousands or tens of thousands plates in each menu without a problem. But if you need to store much more in each menu, then you should go with some of your initial setups.

How to implement a deep populate using the Mongoose, to properly output a M:N database relation?

I am trying to create a basic social media website, with post having different comments, likes, comments also having likes. If the logged in user is the one that made the comment or post, he could be able to delete the post.
So I have to use the deep populate method of mongoose, but the issue I am having is, when the content of the comment is showing, then the name of the user that made that comment is missing.
Post Schema is as follows
content: {
type: String,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
// include the array of ids of all comments in this post schema itself
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment'
}
],
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Like'
}
]
},{
timestamps: true
});
Like Schema is as follows -
const likeSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.ObjectId
},
// this defines the object id of the liked object
likeable: {
type: mongoose.Schema.ObjectId,
require: true,
refPath: 'onModel'
},
// this field is used for defining the type of the liked object since this is a dynamic reference
onModel: {
type: String,
required: true,
enum: ['Post', 'Comment']
}
}, {
timestamps: true
});
User Schema is as follows -
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
name: {
type: String,
required: true
},
avatar: {
type: String
}
}, {
timestamps: true
});
Comment Schema is as follows -
const commentSchema = new mongoose.Schema({
content: {
type: String,
required: true
},
// comment belongs to a user
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
post: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
},
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Like'
}
]
},{
timestamps: true
});
And this is the populate function, on the front end I am trying to display all possible posts with all possible likes and comments, with all the comments also having likes. And obviously the name of the user that made the comment -
let posts = await Post.find({})
.sort('-createdAt')
.populate('user')
.populate({
path: 'comments',
populate: {
path: 'user'
},
populate: {
path: 'likes'
}
}).populate('comments')
.populate('likes');
But in the front end, I am not able to display the User Name that made a particular comment.
Please tell the error.

How to skip the unique constraint validation on same document update

I have an update call as below in my NestJs project to update a mongoose model.
async updateRole(role_id: ObjectId, request: any): Promise<any> {
return this.roleModel.findByIdAndUpdate(role_id, {...request});
}
Here is the request I'm passing
{
"name":"Super-Admin",
"application": "62b2dbfd82045f40ea884334",
"active":true,
"privileges": ["62b2dbfd82045f40ea884334","62b2dbfd82045f40ea884334"],
"updated_by": "Abhilash.Shajan1#gmail.com"
}
Below is my role schema
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
const RoleSchema = new Schema({
name: {
type: String,
required: true
},
application: {
type: Schema.Types.ObjectId,
ref: 'Application',
autopopulate: true,
required: true
},
active: {
type: Boolean,
required: true
},
privileges: [{
type: Schema.Types.ObjectId,
ref: 'Privilege',
autopopulate: true
}],
created_by: {
type: String
},
created_at: {
type: Date
},
updated_by: {
type: String
},
updated_at: {
type: Date
}
});
RoleSchema.index( { name: 1, application: 1 }, { unique: true } );
export { RoleSchema };
I already created a document (This is the only document now present in the roles collection) with the above request. Now I'm trying to update its active field to true.
Since i have unique compound index in the schema, it does not allow me to update the active field, I'm getting unique contraint error on both application and name field.
This error will be meaningful if i have another document with same name and application in the collection, but there is not.
Another way is to pass the active field alone in the request. But it will not help in my case because the UI is always passing the whole fields which include the unchanged values as well.
Any suggestions ?

How can I display the username of a forum?

I want to find out how I can display the username of a user. For example user admin posts a forum, then I would see Created By: admin on the forum page, instead I can only fish out the ID.
I don't know a much about mongoose and I need someone who is familiar with it.
My Forum Model:
You see I have only ref: 'user' and this is grabbing the ObjectId("") from the User.
const forumSchema = ({
forumName: {
type: String,
required: true,
},
forumDescription: {
type: String,
required: true,
},
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
published_on: {
type: String,
default: moment().format("LLL")
},
});
my userModel:
const UserSchema = mongoose.Schema({
userID: {
type: String,
required: true,
},
userName: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
isAdministrator: {
type: Boolean,
deafult: false,
},
});
Front-end :
As you can see only in {forum.user} there I can see the id from the user but I want his name not the id
<footer className="blockquote-footer">
Created by:{forum.user}
Created on:{forum.published_on.substring(0,300)}
</footer>
Since you are using 'ref' to reference the user table. When you are fetching a forum document, use the populate() function in mongoose to get all the user details as a sub-object to the forum document.
example: forumShcema.find({_id:<forum_id>}).populate('user').exec()

Mongoose: Join Operation, populate isn't possible

I'm currently struggling with a project of mine.
I've got a collection called "Games" and one "Participation".
When a user loggs in, he/she should be able to see the games and the individual participation status.
Therefore, I want to join these two collections but I can't use .populate() because I can't enter the neccessary Participation ID in the Games collection due to the fact, that I don't have the participation ID at the time I create a game. (So I would need to save the participation, remember the created ID and insert THIS id in the games collection afterwards)
The other way round would be a good solution (to populate Games in Participation) but initially, there are no participations in these collection, until a user clicks "Participate" or "Not Participate".
Basically I need a SQL query like that:
select * from games g, participation p where g.gamesId = p.gamesId AND p.username = [...]
Is there any possibility to achieve this?
Otherwise I would need to save every participation as a "Game", having the dependent username and his/her participation status in it.
Wouldn't prefer this solution at all.
Thanks in advance!
In case it helps:
Here are my two collections:
Game:
var gameSchema = mongoose.Schema(
{
isHome: { type: Boolean, required: true },
time: { type: String, required: true, max: 100 },
uzeit: { type: String, required: true, max: 100 },
clubId: { type: mongoose.Types.ObjectId, required: true },
enemy: { type: String, required: true, max: 100 },
place: { type: String, required: true, max: 100 },
(participation: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Teilnahme' }])
});
Participation:
var participationSchema = mongoose.Schema(
{
playerAvailable: { type: Boolean, required: true },
clubId: { type: mongoose.Types.ObjectId, required: true },
gameId: { type: mongoose.Types.ObjectId, required: true, ref: 'Game' },
memberName: { type: String, required: true },
}
);

Categories