How to store properties with different languages in mongodb and mongoose - mongodb

This is my schema:
var cvSchema = new Schema({
name: {type: String, required: true},
alias: {type: String, required: true, minlength: 6, maxlength: 6},
profitCentre: {type:Number, min:1000, max:9999},
city: String,
company: String,
profession: {
type: Schema.ObjectId,
ref: 'profession',
required: true
},
});
The profession property is a reference. The profession can have one value, but with several languages. Is there any best practice on how to do this?
I came up with two options:
var professionSchema = new Schema({
values: [
{
lang: {type: String, enum: ['sv', 'en']},
name: {type: String, required: true}
}
]
});
Option two: (en = english, sv = swedish):
var professionSchema = new Schema({
en: 'String',
sv: 'String'
});
The first one is more generic, but I find it difficult to run easy queries (populate etc) on it. It's easier to run queries with the second one. Is there a right or wrong way here?

I don't see either of these being right or wrong and think you should use the solution that fits best with what you are trying to accomplish.
You might even consider checking out this npm package to make things simpler.

Related

mongoose comments and replies schema

I am following this link to understand how to design my schema for a social media type module with comments and replies. https://www.xuchao.org/docs/mongodb/use-cases/storing-comments.html#gsc.tab=0 (This is for mongdb and not mongoose)
I am trying to create a schema like this
const socialSchema = new mongoose.Schema({
Entry_Number: Number,
Player_Name: String,
Player_Message : String,
Player_Fullmessage: String,
Player_ProfilePic : String,
Player_UploadedPic: String,
Player_UploadedVideos: String,
Status_Date: String,
Status_Feeling: String,
Google_Profile: String,
Status_Likes: [{Like_Number: Number, Liked_By: String}],
Status_Comments: [
{Comment_Number: Number,
Comment_By: String,
Comment_Message: String},
replies: [
{Comment_By: String,
Comment_Message: String}
],
],
Friends: { type: Array, default: []},
Shares: { type: Array, default: []},
Shared_Post: String,
Shared_Newmessage: String,
Shared_PostDetails: [{type: Schema.Types.ObjectId, ref: "socialdatas"}]
The problem I am facing is with the replies. My logic tells me that the replies should be a array within the main comments array. However the cods as it is above, gives me an error while compiling. SyntaxError: Unexpected token ':'
Am I approaching this correctly? Any experts that can give me some advice. Thanks.
I would suggest create a separate schemas for comments and players, then you can just use populate() to access data between collections.
but to fix your issue above, it should be like this:
Status_Comments: [{
Comment_Number: Number,
Comment_By: String,
Comment_Message: String,
replies: [
{Comment_By: String,
Comment_Message: String}
]
}]

Looking for MongoDB schema suggestions

I'm relatively new to MongoDB and I'm wondering what the "best" solution would be for handling the following type of data in my database.
Collections:
Users
Lessons
Overview:
Note: Think of the implementation to be similiar to Duolingo or some other learning site.
Users have all the standard generic user information but they also need to track how many points, words learned, percentage complete, and so on, that they have for each given lesson they've started.
Lessons have data like: words learned, total points, words to review, etc.
Picture
Example of what a user would see in the widget when they view a lesson they've already started...
So what's a good way to handle this? I feel that I will need at a minimum a collection for users and lessons, but where would I store that user specific data relating to lessons they've taken?
What I've thought of so far ...
// user collection
const UserSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
firstName: { type: String },
lastName: { type: String },
gender: { type: String, enum: ['male', 'female', 'other'] },
admin: Boolean,
address: {
street: String,
city: String,
state: {
type: String,
uppercase: true,
required: true,
enum: statesArray,
},
zip: Number,
},
});
// lesson_results collection
const LessonResultsSchema = new mongoose.Schema({
user_id: Schema.Types.ObjectId,
results: [
{
id: Number,
lesson_id: Schema.Types.ObjectId,
pointsEarned: Number,
wordsLearned: Number,
wordsToPractice: [
{
id: Number,
correct: Number,
incorrect: Number,
bookmarked: Boolean,
},
],
},
],
});
// lesson collection
const LessonSchema = new mongoose.Schema({
title: String,
description: String,
totalPoints: Number,
totalWords: Number,
words: [
{
id: Number,
word: String,
points: Number
}
]
})
// if logged in
// find user in user collection
// find user's results in lessonsResults collection by using user_id
// iterate over each result to find their lesson & lesson's data
// combine data and send to frontend
// calculate percentage complete + other calculations
// render aggregate data on screen
I'm curious how you would resolve this.
Apologies if it's a bit long-winded! (+ hopefully the examples make sense)
You need to have the reference of user in LessonSchema, so that you can track how many lessons are taken by a user.
const LessonSchema = new mongoose.Schema({
user:{type:mongoose.Schema.Types.ObjectId,ref:'UserSchema',required:true},
title: String,
description: String,
totalPoints: Number,
totalWords: Number,
words: [
{
id: Number,
word: String,
points: Number
}
]
})
And you need to maintain a FLAG in LessonResultsSchema to track whether a user has completed that lesson or not. Once the lesson gets completed, you need to update the pointsEarned so that you can have the updated points data.
const LessonResultsSchema = new mongoose.Schema({
user_id: Schema.Types.ObjectId,
completed:{type:Boolean, default:0},
results: [
{
id: Number,
lesson_id: Schema.Types.ObjectId,
pointsEarned: Number,
wordsLearned: Number,
wordsToPractice: [
{
id: Number,
correct: Number,
incorrect: Number,
bookmarked: Boolean,
},
],
},
],
});

Mongoose Object Array won't work on Postman

After completing a course on MEAN Stack, I'm working on making my own webapp - a recipe page. I've designed my models, but when I try to fill the database with a new Recipe it just won't work. The main issue is the way I want to store ingredients, they'll be stored on one of the tables, then each recipe has its list of ingredients and amounts for each. For example, to make some toast you need, say "50 grs. of Butter and 4 slices of Bread". This is the Schema I'm using:
var RecipeSchema = Schema({
name: String,
desc: String,
author: { type: Schema.ObjectId, ref: 'User' },
category: { type: Schema.ObjectId, ref: 'Category' },
ingredients: [{ amount: String, ingredient: { type: Schema.ObjectId, ref: 'Ingredient' }}],
steps: [String],
image: String,
thumbnail: String,
portions: Number,
difficulty: Number,
cookingTime: Number,
comment: String
});
When I go in Postman and try to fill the "Toast Recipe" entry, I have the following:
name:Toast
desc:Toast is a common breakfast staple.
author:5cad791a7b2e651f7803f5de
category:5cb1ff8f484a172984178a97
ingredients:[{"amount": "4 slices", "ingredient": "5cb1ffdb484a172984178a98"}, {"amount": "35 grs.", "ingredient": "5cb2000d484a172984178a99"}]
steps:['Toast the bread in the oven.','Spread some butter on each toast.']
image:'null'
thumbnail:'null'
portions:1
difficulty:1
cookingTime:15
comment:'null'
But I keep getting a "cast Array" error. What could be the issue? Is it a problem with my model, with Postman, or with the way I'm sending the Array?
EDIT:
Apparently it was a problem whit the way I posted my arrays in Postman. After some more tests I managed to upload a full recipe in JSON format. The structure is correct (but what Juan suggests can be used too, to make the code cleaner).
I'am not completely sure, but when I worked with mongoose, inner objects had a new Schema object inside, in this case it would on ingredients
const IngredientSchema = new Schema({
amount: String,
ingredient: { type: Schema.ObjectId, ref:'Ingredient' }
});
const RecipeSchema = new Schema({
name: String,
desc: String,
author: { type: Schema.ObjectId, ref: 'User' },
category: { type: Schema.ObjectId, ref: 'Category' },
ingredients: [ IngredientSchema ],
steps: [String],
image: String,
thumbnail: String,
portions: Number,
difficulty: Number,
cookingTime: Number,
comment: String
});

Products with different variants schema

I am trying to create an e-commerce website using MongoDB. I have created a Product and variant model, my question is how can I search the product with variant, for example for "Size" user can add variant value as "S" or "Small". How can I search the product which has for example small product in this case as a product have many variants, how can I list eg. all products with small size. Here is my variant model.
var variantSchema = Schema({
name: {
type: String,
required: true,
unique: true
},
count: {type: Number, default : 0}
});
And my Product Schema is:
var productSchema = Schema({
sku: {
type: String,
lowercase: true
}, //, required: true, unique: true
name: {
type: String,
lowercase: true,
max: 65,
required: true
},
slug: {
type: String,
lowercase: true,
unique: true,
index: true,
slug: "name",
slug_padding_size: 3
},
status: Boolean,
listPrice: Number,
description: {
short: {
type: String,
trim: true,
lowercase: true
},
long: {
type: String,
trim: true,
lowercase: true
}
},
images: [],
categoryId: {
type: Schema.Types.ObjectId,
ref: 'Category'
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
},
isActive: Boolean,
vars: [
{
varId : {
type: Schema.Types.ObjectId,
ref: 'Variants'
},
values: [
{
value : String,
image:[]
}
]
}
]
});
Based on your comment.
You can distinguish "Small" and "small" by ignoring case sensitive.
UserModel.findOne({
email: {'$regex': "^"+ email +"$", $options:'i'}
}, function (err, data) {
callback(err, data)
});
But you can not match S with Small.
Approach 1:
You need to maintain the possible words that you want to consider as Small. Maybe by inserting in Variant Schema an array ["S", "Small"] like this. But in this scenario. You must have to caution about S. S can be anything. (I am not recommended this approach)
Approach 2:
I would like to suggest making one schema (SizeSchema) that can present the size. for e.g. Small, Large, Extra small, Extra Large etc... And reference that SizeSchema to VariantSchema and ProductSchema to VariantSchema. (Triple relationship). And this would be fixed for the end user. No one will have an option like "S".
Hope this may help you.

Modeling with MongoDB and Mongoose

I have a simple app which lists tour guides and reviews left by users about each guide. Any user can give be a guide and can give reviews. My scheme for a user is:
var User = new mongoose.Schema({
firstName: { type: String, required: true, unique: true },
lastName: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true}
isGuide: Boolean,
rating: {type: Number, "default": 0, min: 0, max: 5},
reviews: [reviewSchema]
});
var Review = new mongoose.Schema({
userId: {type: Schema.ObjectId, ref: 'User'},
author: {type: String, required: true},//contatenation of firstName and lastName of user that wrote review
rating: {type: Number, required: true, min: 0, max: 5},
reviewText: {type: String, required: true},
createdOn: {type: Date, "default": Date.now}
});
mongoose.model('User', User);
I want to be able to:
1/ show a guide and all that guide's reviews
2/ show all a user's reviews
3/ show all guides a user has reviewed
I think my schema above is fine for 1. But is it suitable for 2 and 3? Am I understanding the MonboDB philosophy correctly?