Mongoose use only createdAt timestamp - node.js

I have the following message schema in mongoose:
var messageSchema = mongoose.Schema({
userID: { type: ObjectId, required: true, ref: 'User' },
text: { type: String, required: true }
},
{
timestamps: true
});
Is there anyway to ignore the updatedAt timestamp? Messages won't be updated so updatedAt will be wasted space

Maybe even better with Mongoose v5 is to do the following;
const schema = new Schema({
// Your schema...
}, {
timestamps: { createdAt: true, updatedAt: false }
})

Edit I've amended the answer to reflect the better option to use the default as per #JohnnyHK
You can handle this yourself by declaring the createdAt (or whatever you want to call it) in your schema:
mongoose.Schema({
created: { type: Date, default: Date.now }
...
Alternatively we can also update values on new document in a pre save hook:
messageSchema.pre('save', function (next) {
if (!this.created) this.created = new Date;
next();
})
Along those lines is also the flag isNew which you can use to check if a document is new.
messageSchema.pre('save', function (next) {
if (this.isNew) this.created = new Date;
next();
})

Older topic but there may be a better option depending on your schema...
If you're sticking with the default of having mongodb/mongoose auto-gen _id, there's already a timestamp built in. If all you need is "created" and not "updated" just use...
document._id.getTimestamp();
From MongoDB docs here...
ObjectId.getTimestamp()
And Here... stackoverflow

Mongoose timestamp interface has these optional fields.
interface SchemaTimestampsConfig {
createdAt?: boolean | string;
updatedAt?: boolean | string;
currentTime?: () => (Date | number);
}
We can pass the boolean for the field we want(createdAt: true and updatedAt: true will add both fields).
We can use the currentTime function to overwrite the date format.
example:
import mongoose from 'mongoose';
const { Schema } = mongoose;
const annotationType = ['NOTES', 'COMMENTS'];
const referenceType = ['TASKS', 'NOTES'];
const AnnotationSchema = new Schema(
{
sellerOrgId: {
type: String,
required: true,
},
createdById: {
type: String,
required: true,
},
annotationType: {
type: String,
enum: annotationType,
},
reference: {
id: { type: String, index: true },
type: {
type: String,
enum: referenceType,
},
},
data: Schema.Types.Mixed,
},
{ timestamps: { createdAt: true },
);
const AnnotationModel = mongoose.models.annotation || mongoose.model('annotation', AnnotationSchema);
export { AnnotationModel, AnnotationSchema };

Related

How to add a new field to an existing MongoDB document using Mongoose?

I have tried so many times to add new field to the existing MongoDB document but I failed. I tried following code to do the job but nothing happened.
Here is the User model.
const UserSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
},
{ timestamps: true }
);
Here is the code to add new field to the document.
const updateDocument = async () => {
const updatedUser = await User.findOneAndUpdate(
{ _id: "63eb30f466127f7a0f7a9b32" },
{
$set: { lastName: "syed" },
}
);
console.log(updatedUser);
};
updateDocument();
NOTE 1: lastName field does not exist in the MongoDB document and in the UserSchema. I want to add that field to the MongoDB document.
NOTE 2: The same code works when I update the existing field inside the document but it does not work when adding new field.
You need to pass strict:false as an option to findOneAndUpdate.
According to the mongoose doc:
The strict option, (enabled by default), ensures that values passed to our model constructor that were not specified in our schema do not get saved to the db.
const updatedUser = await User.findOneAndUpdate(
{ _id: "63eb30f466127f7a0f7a9b32" },
{
$set: { lastName: "syed" },
},
{ strict: false }
);
An alternative way is to pass this parameter when you defined the schema:
const UserSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
},
{ timestamps: true, strict: false }
);

How to Auto update Value in mongodb Document

I have a field in my mongoose schema called "active" and I wanted to know if there is any way that every date expired in a particular document, then the "active" field would change to false. how should I do that if so, What is the easiest way to do this? else, what is recommended?
And below is my Schema;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const schema = new Schema({
user_id: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
hash: {
type: String,
required: true
},
active: {
type: Boolean,
},
role: {
type: String,
required: true
},
createdDate: {
type: Date,
default: Date.now
}
});
schema.set('toJSON', { virtuals: true });
module.exports = mongoose.model('User', schema);
You can do this with a feature in mongo called Change Streams that allow you to access real-time data changes. You can subscribe to the changes of a single collection or the whole database and react to them. You can also filter for specific changes or transforms. For your case an example would be something like this.
EDIT: Change streams implementation is only available on replica sets.
const pipeline = [
{ $match: { expire_date: {$lt: Date.now()} } },
{ $set: { active: false } }
];
const collection = db.collection('user');
const changeStream = collection.watch(pipeline);
changeStream.on('change', next => {
// process next document
});

MissingSchemaError: Schema hasn't been registered for model during populate

I have two models
1.PageType Model
module.exports = (mongoose) => {
const pageTypeSchema = new mongoose.Schema({
title: {
type: String,
key: {
type: String,
required: true,
},
}, {
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
});
return mongoose.model('PageType', pageTypeSchema);
};
WorkFlow Model
module.exports = (mongoose) => {
const workFlowSchema = new mongoose.Schema({
title: {
type: String,
default: null,
},
key: {
type: String,
default: null,
},
level: {
type: Number,
required: true,
},
page_type_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'PageType',
},
}, {
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
});
return mongoose.model('WorkFlow', workFlowSchema);
};
But when I try to use populate it throws Schema hasn't been registered for model PageType
async getFlowById(flowId) {
const result = await this.workFlow.findById(flowId).populate('page_type_id').exec();
return result;
}
Can anyone please help me with this??
In app.js the models are included before routes also PageType model is also declared before WorkFlow model
You typed wrong collection name. Collection name is Workflow and you are trying to findById at workflow. So i think Workflow should be there. Just try with that.

How to update an array inside of a mongoose schema?

How to update an array inside a mongoose schema with updateOne?
I have one model on my Node.Js application that I've made with mongoose schema.
One of the fields of my schema is an array:
guestsNames: []
I'm already able to save items inside of this array but I didn't find a way to update the items inside of it.
Here is my whole schema:
const screenImageSchema = mongoose.Schema({
company: {
type: String,
require: true,
trim: true
},
guestsNames: [],
imageName: {
type: String,
require: true
},
defaultImageName: {
type: String,
require: true
},
date: {
type: String,
default: Date.now,
require: true
},
activated: {
type: String,
default: 'Enabled'
},
wsType: {
type: String,
default: 'Image'
}
}, {timestamps: true});
...and my updateOne method:
screenImageSchema.methods.updateOne = function(id, screenImage) {
const updatedScreenImage = {
company: screenImage.company,
guestsNames: screenImage.guests,
imageName: screenImage.imageName,
defaultImageName: screenImage.defaultImageName,
date: screenImage.date,
activated: screenImage.activated,
wsType: screenImage.wsType
}
ScreenImage.updateOne(id, updatedScreenImage, {new: true});
}
The 'screenImage' parameter passed to the function is an object with all information that I need, including an array with all strings for guestsNames (I've already checked if the parameters are being passed correctly to the object and they are). All fields are being updated with this piece of code except the guestsNames field. What am I doing wrong and how can I make the guestsNames array be updated correctly?
Cheers.
You can update directly your array like this
ScreenImage.updateOne(id, { $set : { guestNames : newArray }})
You need to use $set to replace the value of a field, see this mongoDB $set
try this if it works
screenImageSchema.methods.updateOne = function(id, screenImage) {
const updatedScreenImage = {
company: screenImage.company,
guestsNames[0]: screenImage.guests,
imageName: screenImage.imageName,
defaultImageName: screenImage.defaultImageName,
date: screenImage.date,
activated: screenImage.activated,
wsType: screenImage.wsType
}
ScreenImage.updateOne(id, updatedScreenImage, {new: true});
}

How can I auto-case key names when saving to Mongoose?

I have an object:
{ SKU: 'TR1234',
Description: 'Item 1',
UoM: 'each',
client_id: '531382e3005fe0c926bd3957',
Meta: { Test: 'test1', Image: 'http://www.aol.com' } }
I'm trying to save it given my schema:
var ItemSchema = new Schema({
sku: {
type: String,
trim: true,
},
description: {
type: String,
trim: true,
},
company_id: {
type: Schema.ObjectId,
ref: 'Client',
},
createdOn: {
type: Date,
default: Date.now
},
updatedOn: {
type: Date,
default: Date.now
}
}, {versionKey: false});
But it doesn't save and I assume it's because of the capitalized key names. However, those are dynamically generated from a CSV which is parsed with https://github.com/Keyang/node-csvtojson
Ideas?
You can also just use a setter in your mongoose schema, like that:
function toLower (v) {
return v.toLowerCase();
}
var UserSchema = new Schema({
email: { type: String, set: toLower }
});
Just apply it to your fields.
There is also one more approach, just:
email : { type: String, lowercase: true }
Update for keys:
If you would like to change keys, you should the approach likes 'ecdeveloper' mentioned below. My answer was for values, so it makes sense to give this reputation to 'ecdeveloper'. Sorry for confusing.
Here is one more approach without creating a new object:
Object.prototype.keysToUpper = function () {
var k;
for (k in this) {
if (this.hasOwnProperty(k))
this[k.toLowerCase()] = this[k];
delete this[k];
}
return this;
};
What about calling toLowerCase() on each key from your object, and build a new object with lower case keys?
// Assumy your object name is obj
var newObj = {};
Object.keys(obj).forEach(function(key) {
newObj[key.toLowerCase()] = obj[key];
});
// Here you can save your newObj

Resources