How to sustainably organise user schema in mongoose - javascript

I have a user which should have the following fields and currently has following schema:
const UserSchema = new Schema(
{
email: {
type: String,
required: true,
index: { unique: true },
lowercase: true,
},
isVerified: { type: Boolean, default: false }, // whether user has confirmed his email
name: { type: String, required: false },
password: { type: String, required: true, minLength: 6 }, // object with next two included?
passwordResetExpires: Date,
passwordResetToken: String,
roles: [{ type: 'String' }], // Array of strings?
username: { type: String, required: false },
token: [{ type: String, required: false }], // used to send verification token via email
},
{ timestamps: true },
);
So yes, what is the world's default standard for organising user schemas. This schema's fields are pretty common, right?

Related

How to store empty array in mongodb

I want to store empty array in user schema's friends key. But, mongoose won't let me to add empty array of friends.
Here's my User schema
const userSchema = mongoose.Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
userName: {
type: String,
unique: true,
required: true,
},
email: {
type: String,
required: true,
unique: true,
validate: [validator.isEmail, "Please enter a valid Email"],
},
password: {
type: String,
required: true,
minlength: [6, "Password must be at least 6 characters"],
},
friends: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
unique: true,
},
],
});
And here's my code to pull data from array and save empty array
const index = req.user.friends.findIndex(friend => friend.toString() === req.params.id);
if(index !== -1){
req.user.friends.splice(index, 1);
}else{
req.user.friends.push(req.params.id);
}
const user = new User(req.user);
await user.save({validateBeforeSave: false});
return res.json({success: true});
specify default value instead
friends: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
unique: true,
default: []
},
],

How to make a mongoose schema of arrays with nested subdocuments

I want to store an array of nested subdocuments such as the one down bellow:
[
{"2021-02-01income":{"value":37.95,"tax":0,"type":"income"}},
{"2021-03-01income":{"value":38.25,"tax":0,"type":"income"}},
{"2021-03-08fund": {"value":-78,"type":"fund","transaction":"610378deead56742a898443b"}},
{"2021-04-01income":{"value":38.53,"tax":0,"type":"income"}},
{"2021-07-01income":{"type":"income","tax":0,"value":134}},
]
I came up with the following schema which is not working, because as you can see the array of objects is based on unique keys nested objects...
Is there any workaround I can try:
const incomeSchema = mongoose.Schema({
type: { type: String, required: true },
value: { type: Number, required: true },
tax: { type: Number, required: false },
transaction: {
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'Transaction',
},
});
const investmentSchema = mongoose.Schema(
{
incomes: [{ type: incomeSchema }],
name: { type: String, required: true },
user: {
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'User',
},
account: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Account',
},
broker: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Broker',
},
type: { type: String, required: true },
rate: { type: String, required: true },
indexer: { type: String, required: true },
investment_date: { type: Date, required: true },
due_date: { type: Date, required: true },
initial_amount: { type: Number, required: true },
accrued_income: { type: Number, required: false, default: 0 },
taxes: { type: Number, required: false, default: 0 },
},
{ timestamps: true }
);
const Investment = mongoose.model('Investment', investmentSchema);
I found a workaround.... I just setted the _id in the Transaction schema as string and now everything is working... I mean I can update the array of neste subdocuments

can a mongoose schema field reference more than one other models

I have a mongoose schema field called "bookmarks" and I would like it to reference more than one model. for example, if I have 2 other models named "post" and "complain". I would like the user to be able to bookmark both of them.
const userSchema = new mongoose.Schema({
fullname: {
type: String,
required: true,
trim: true,
lowercase: true
},
username: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
bookmarks: [{
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'Post'
}],
})
below is a post model, where users can post things in general
const postSchema = new mongoose.Schema({
body: {
type: String,
required: true,
trim: true,
lowercase: true
}
})
below is a complain model, where users can post a complain
const complainSchema = new mongoose.Schema({
body: {
type: String,
required: true,
trim: true,
lowercase: true
}
})
How can I get the bookmarks field in the user model to be able to get the object id of both the complain model and the post model?
You can nest those two models in userSchema itself just like you are doing with bookmark schema .
You can also refer to this link , i hope it will resolve your query.
Link - : What is the proper pattern for nested schemas in Mongoose/MongoDB?
Here is the correct way to achieve this.
First remove bookmarks
Add this
ref: {
kind: String, // <-- Model Name post,complain
item: {
type: mongoose.Schema.Types.ObjectId,
refPath: 'ref.kind',
fields: String,
},
},
When you want to fetch the records,you can use populate
model.User.find({})
.populate({ path: 'ref.item' })
.then(data=>{console.log(data)})
.catch(err => {console.log(err)});

What's the difference between document.property and document.get('property')?

I have a mongoose document that has timestamps option enabled. I want to make decisions based on this timestamps but I noticed something weird according to my understanding.
I tried to get those values the traditional way (document.createdAt) but that returns undefined. But if I use document.get('createdAt') the value comes as in the database. The docs don't say anything about this. My question is: ¿Why timestamps behave this way?
Edit
The schema I'm using has an array of embedded schemas:
const Customer = new mongoose.Schema({
roles: {
type: [{
type: String,
enum: 'app b2b iot'.split(' '),
}],
default: 'app',
set: (value = []) => (value.includes('app')
? value
: value.concat('app')),
},
email: {
address: {
type: String,
trim: true,
lowercase: true,
set(email) {
this._previousEmail = this.email.address
return email
},
},
verified: {
type: Boolean,
},
token: String,
},
nickname: {
type: String,
trim: true,
},
recoveryToken: String,
gender: String,
birthday: String,
lastLogin: Date,
isAnonymous: {
type: Boolean,
default: false,
},
devices: [Device],
});
Device schema:
const Device = new mongoose.Schema({
customer: {
type: ObjectId,
ref: 'Customer',
required: true,
},
handle: {
type: String,
},
platform: {
type: String,
required: true,
set: toLowerCase,
},
info: Mixed,
smartFilterTags: [{
type: String,
}],
paidUntil: Date,
nh: {
tier: String,
_id: {
type: ObjectId,
},
location: {
type: {
type: String,
enum: ['Point'],
default: 'Point',
},
coordinates: [{
type: Number,
}],
},
})
I have a base plugin that apply when I compile models:
function basePlugin(schema) {
schema.add({
archivedAt: Date,
})
schema.set('timestamps', true)
schema.set('toJSON', {
virtuals: true,
})
schema.set('toObject', {
virtuals: true,
})
}

Updating nested array's field

I have a schema
const RoomSchema = mongoose.Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
},
author: {
type: String,
required: true
},
resource: {
type: String
},
posts: {
type: Array,
default: []
},
url: {
type: String
},
created_at: {
type: String,
required: true
}});
Field 'posts' is another document in my db, defined by the following schema:
const PostSchema = mongoose.Schema({
header: {
type: String,
required: true
},
body: {
type: String,
required: true
},
author: {
username: {type:String, required: true},
_id: {type:String, required:true}
},
room: {
type: String,
required: true
}});
So, I'm trying to create a query that would update fields of certain post inside posts array inside room. I've already tried suggested here, thought without results. I would appreciate any help on the subject
Room.update({ '_id': roomId, 'posts._id': postId },
{ $set: { 'posts.$.header': newHeader, 'posts.$.body': newBody } },
callback);

Categories

Resources