In my Mongoose schema I'm using Date.now to insert a user based on creation time. For some strange reason (unknown to me), the time is one hour behind. I'm thinking it's because I'm (GMT+1) but and my Express/Node/Mongo setup must be standard GMT time, or maybe not. Has anyone come across this before?
User = new Schema({
fullName: {
type: String,
required: true
},
password: {
type: String,
required: true
},
emailAddress: {
type: String,
unique: true,
required: [true, 'Email address is required.']
},
uniqueURL: {
type: String,
required: true,
unique: true
},
created: {
type: Date,
default: Date.now
}
});
Related
I am building a user model in mongoose, nodesjs where the each user has set of contacts which are actually users, each contact is a user.
I have two approaches
Approach 1
Is to add the contacts as an array of user objects to reference User model in the user model as an array of contacts but i want to determine the Date and time of when was the contact was added, i don't know how to add that
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter a name'],
},
username: {
type: String,
match: [
/^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{0,29}$/,
'Please enter a valid user name',
],
},
password: {
type: String,
required: [true, 'Please enter a password'],
minLength: 6,
select: false,
},
role: {
type: String,
enum: ['user'],
default: 'user',
},
resetPasswordToken: String,
resetPasswordExpire: Date,
allowAutoApproveContacts: {
type: Boolean,
default: false,
},
createdAt: {
type: Date,
default: Date.now,
},
contacts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
],
});
**Approach 2 **
is to create a new model Contact and reference the user model as user and the User model again as the contact, and add the addedAt Date to determine when was the contact was added and maybe add other properties
const ContactSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
contact: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
addedAt: {
type: Date,
default: Date.now,
},
autoAllowed: Boolean,
});
Can you please help me with which approach is the correct approach or if you can suggest a new one
I know, if i want to set the expire time for one collection with the expires property like so:
new Schema({
token: {
type: String,
required: true
},
createdAt: {
type: Date,
expires: '10s',
default: Date.now
}
});
But, how can i set the expire time for one property in a collection?
For example i have an schema with username, email and a array of authentification tokens. I want every token to be deleted from the creation date after 10s. I tried:
new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
tokens: [{
createdAt: {
type: Date,
expires: '10s',
default: Date.now
},
auth: {
type: String,
required: true
},
token: {
type: String,
required: true
}
}]
});
But every time the complete collection will be deleted, not the token object.
You can create a separate collection for holding authentication tokens, and maintain a one-to-many relationship between user and token collections.
you can cascade insert/update/delete using pre/post middlewares, so when token expires de-reference token in user
user schema
const UserSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
tokens: [
{ type: Schema.Types.ObjectId, ref: 'Token' }
]
});
token schema (make sure you have created ttl index on createdAt)
const TokenSchma = new Schema({
user : {
type: Schema.Types.ObjectId, ref: 'User'
},
createdAt: {
type: Date,
expires: '10s',
default: Date.now
},
auth: {
type: String,
required: true
},
token: {
type: String,
required: true
}
}
);
I have build a schema as follows:
const UserInfoSchema = new Schema({
email: { type: String, required: true, unique: true },
username: { type: String, required: true, unique: true },
userId: { type: Schema.Types.ObjectId, ref: 'User'},
displayName: { type: String, required: true },
profilePic: {
filename: {type: String},
url: {type: String}
},
created_at: Date,
updated_at: Date
})
What I need here is once the fields such as email, username and userId are saved, should not be modified. Is there anything pre-build in mongoose for this kind of feature?
I have done some research on schema.pre('update', (next) => {}), but got nothing really useful/don't know if one can use for the mentioned feature. Any help on this matter is greatly appreciated. Thanks in advance.
There is an easier way
when you save the Schema, you can set the field as immutable, like this
const UserInfoSchema = new Schema({
email: { type: String, required: true, unique: true, immutable:true },
username: { type: String, required: true, unique: true, immutable:true },
userId: { type: Schema.Types.ObjectId, ref: 'User', immutable:true},
displayName: { type: String, required: true },
profilePic: {
filename: {type: String},
url: {type: String}
},
created_at: Date,
updated_at: Date
})
it won't throw any error, if you want it you should check it elsewhere, but when you try to modify the immutable fields, it wont be changed at all
for(const key in userUpdates) {
switch(key) {
case 'username':
case 'email':
throw new Error('These field/s cannot be changed anymore');
}
}
User.findByIdAndUpdate(id, userUpdates, { new: true, runValidators: true });
I have this mongoose schema, I added updated_by and created_by, but for some reason when I save models from client to server, those fields aren't visible:
userSchema = mongoose.Schema({
role: {
type: String,
enum: ['Admin', 'Owner', 'User']
},
username: {
type: String,
unique: true,
required: true,
validate: [validation.usernameValidator, 'not a valid username']
},
passwordHash: {
type: String,
required: true,
validate: [validation.passwordValidator, 'not a valid password']
},
email: {
type: String,
unique: true,
required: true,
validate: [validation.emailValidator, 'not a valid email address']
},
firstName: {
type: String,
required: false
},
lastName: {
type: String,
required: false
},
registered_at: {
type: Date,
default: Date.now
},
created_by: {
type: String,
required: false
},
updated_by: {
type: String,
required: false
},
created_at: {
type: Date,
default: Date.now
},
updated_at: {
type: Date,
default: Date.now
}
},
{
autoIndex: false
});
is this normally a problem? Do I have to somehow rebuild something with Mongoose or MongoDB in order for them to pick up the new properties on this model?
Of course, I did restart the mongoDB server, but that didn't do anything.
In any case, if you save your User model, the fields with actual values shown in MongoDB will be the ones you set a value for yourself when saving the model OR the fields with a default value set in your userSchema.
So, just to clarify on this:
address: { type: String, default: ' ' }
will be shown in MongoDB with a value of ' ' unless you set a specific address when saving your User model.
But,
address: String
will NOT be shown in MongoDB unless you set a specific address when saving your User model.
EDIT
Thanks to Matthew for pointing it out, actually upsert behavior is indeed the following:
If upsert is true and no document matches the query criteria, update() inserts a single document.
I Have schema design as below. I have posts array which is reference to the post model. Is it good idea to put it in User schema or should I not include as it is always growing as users add their post. I guess I should only put accesstokens in reference and not posts. Am I thinking right?
var UserSchema = new Schema({
username: {
type: String,
unique: true,
required: true,
lowercase: true,
trim: true
},
encrypted_password: {
type: String,
required: true
},
salt: {
type: String,
required: true
},
email: {
type: String,
unique: true,
required: true,
lowercase: true,
trim: true
},
mobile: {
type: Number,
unique: true
},
bio: {
type: String
},
created: {
type: Date,
default: Date.now
},
access_tokens: [{type: Schema.Types.ObjectId, ref: 'AccessToken'}],
posts: [{type: Schema.Types.ObjectId, ref: 'Post'}]
}, { collection: 'users' });
You should have a separate collection for Posts but you should keep the access_tokens within the user schema. One good reason you might consider separating the posts into its own collection is there are many use cases where you will query for just posts. However, with access_tokens, they will always be tied to a user.
tldr;
Posts should have their own schema
Access tokens should be in user schema
Hope that helps!