Mongoose delete records after certain time - node.js

I have a mongoose Schema which looks like this:
const USERS_DATA = new Schema({
_id: Number,
name: String,
img: String,
date: Date,
phone: String,
article: String,
createdAt: {
type: Date,
required: true,
default: Date.now,
index: { expires: '3d' }
}
},
{
collection: "users",
_id: false,
}
);
I need to push data to this schema.
const User = mongoose.model("users", USERS_DATA);
function pushToDB() {
const newUser = new User({
name: INPUT.name,
img: INPUT.img,
date: INPUT.date,
phone: INPUT.phone,
article: INPUT.article,
});
newUser.save(function (err) {
mongoose.disconnect();
if (err) return console.log(err);
});
}
This data have to be deleted after 3 days when it was pushed to database. How to implement it in node.js? I found it really confusing and tried lots of code. Any answers are appreciated! Thanks
P.S. I use mongoDb Atlas

You should separate the process to push the data into the database from the process to delete it after 3 days. You have already the first part :).
For the second part, you can write a function deleteOldDocument. This function will query for documents in DB that are created for 3 days or more, and delete them. Then, you can run this function periodically, 1 time per day for example.
The pseudo-code, in case you need it :
async function deleteOldDocument() {
const 3DaysAgo = ...; // here you can subtract 3 days from now to obtain the value
// search for documents that are created from 3 days or more, using $lt operator
const documentToDelete = await User.find({"created_at" : {$lt : 3DaysAgo }});
// delete documents from database
.....
// recall the function after 1 days, you can change the frequence
setTimeOut(async function() {
await deleteOldDocument();
}), 86400);
}
// call deleteOldDocument to start the loop
deleteOldDocument();

Related

Insert same records multiple times to the Mongo database with NodeJs

I want to achive funcionality, where user in the frontend writes how many posts he want to insert in the database.. He can write 1, 5, 10, 15,.. up to 50 same posts.
The posts are then the SAME in the database, just this manually generated _id is different.
At first I thought that it can be done just like that:
exports.addPost = async (req: any, res: any) => {
try {
const newPost = new Post({
title: req.body.title,
description: req.body.description,
author: req.body.author,
});
for (let i: number = 0; i < 5; i++) {
await newPost .save();
}
res.status(201).json(newContainer);
} catch (err) {
res.status(400).json(err);
}
};
Post schema:
const PostSchema = new mongoose.Schema({
title: { type: String, required: true },
description: { type: String, required: true },
author: {
type: Schema.Authors.ObjectId,
ref: "Authors",
required: true,
},
});
module.exports = mongoose.model("Posts", PostSchema);
but I am not sure, if this is really the way to go.. What is some good practice for this (assuming that the number 5 in for loop will come in req.body.. So from user input.
Thanks
You can just use the following code:
try {
await Post.create(
new Array(5).fill(true).map((_) => ({
title: req.body.title,
description: req.body.description,
author: req.body.author,
}))
);
res.status(201).json(newContainer);
} catch (err) {
res.status(400).json(err);
}
model.create does accept passing an array of (new) documents to it. By mapping a new array of size 5 (or depending on user input) to your custom document and passing it to the create function will result in multiple documents created. A huge benefit is that you only have to perform one single database call (and await it).

how to insert multiple JSON objects to one property of a schema?

I have a requirement to store multiple JSON objects in a property of schema.
take this example...
const Schema = require("mongoose").Schema;
const Student= Schema({
student_id: String,
name:String
attendance:[
{
date: Date,
Status: String
}
]
});
I need to insert attendance of individual student which looks like this..
student_id: student_001,
name:'Joe'
attendance:[
{
date: 24-10-2018,
status: 'Present'
},
{
date: 25-10-2018,
status: 'Absent'
},
//list goes on
]
I am using NodeJs as Backend, EJS template as front end and mongodb database. Date and Status comes when user submits data from front end. So I am having hard time writing my post request. Any types of comments / suggestions / change of model structure are welcome. Thank you.
You can create a separate attendance Schema.
const Schema = require("mongoose").Schema;
const AttendanceSchema = new Schema({
date: Date,
status: String
});
const StudentSchema = new Schema({
student_id: String,
name:String
attendance:[AttendanceSchema]
});
const Student = mongoose.model('Student', StudentSchema);
Add a new Student.
let newStudent = new Student({
student_id: student_001,
name:'Joe'
});
newStudent.save();
Update attendance:
let att1 = {
date: 24-10-2018,
status: 'Present'
};
// Here 'id' is id of particular student.
Student.update({ _id: id }, { $push: { attendance: att1 } })
.then(() => console.log("Success"))
.catch(err => console.log(err));
At some point later:
let att2 = {
date: 25-10-2018,
status: 'Absent'
};
// Here 'id' is id of particular student.
Student.update({ _id: id }, { $push: { attendance: att2 } })
.then(() => console.log("Success"))
.catch(err => console.log(err));
I suggest you to change the model structure to be normalized.
This will improve your experience in future statistics querying.
Also, one more suggestion - do not use string indentifiers in mongoDB, this can cause a headache in maintaining their uniqueness. Mongo has automated _id property assigning to each document, you could use it if you need to indentify any object.
Considering my suggestions - the code will look like:
const Schema = require("mongoose").Schema;
const Student = Schema({
name: String
});
const Attendance = Schema({
date: Date,
status: String,
student_id: {
type: Schema.Types.ObjectId,
ref: 'Student'
}
})
Then, you could simply create attendance records assigned to the student :
const attendance = new AttendanceModel({
date: new Date('05/20/2018'),
status: "present",
student_id: "somestudentid"
});

Mongoose can't save document to the database for one particular collection

I have a function
function generateInvoice(data) {
const cdate = new moment.tz('GMT').toDate();
let invoiceData = {
date: cdate,
paidStatus: true,
amount: data.amount,
userId: data.userId
}
if (data.planName && data.planTypeName) {
invoiceData.item = `${data.planName} - ${data.planTypeName}`
invoiceData.quantity = data.seats || data.slots;
}
if (data.credits) {
invoiceData.item = 'Credits';
invoiceData.quantity = data.credits;
}
return Invoice.create(invoiceData).then((data)=>{
data.invoiceId = data._id.toString().slice(-5);
return data.save().then((data)=>{console.log(data); return data.invoiceId}).catch((err)=>{
throw new ErroWithStatusCode(500, 'Sorry, we seem to be facing some issue right now. Please, try again later.', err);
})
})
}
and this is how I am using this function
return generateInvoice(invoiceData).then((data)=>{
newBooking.orderId = data;
id = data;
return newBooking.save().then((booking) => {
return booking;
}).catch((err) => {
throw new ErroWithStatusCode(500, 'Sorry, we are facing some issue right now. Please try again later.')
})
});
The issue is that I can't find invoiceData in my invoices collection. The data in the callback function of then block is the document, but I can't find the same document in the invoices collection.
All the promises are getting resolved. It is not falling in the catch block, I am receiving valid data from Invoice.create(invoiceData).
Also, newBooking.save() function is working as expected. So, that's what is bothering me the most, as to why is it not working for one specific collection.
What could be the reason behind it?
EDIT: This is the invoice schema
const InvoiceSchema = new Schema({
item: String,
paidStatus: Boolean,
quantity: String,
amount: Number,
invoiceId: String,
userId: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
date: {type: Date, default: Date.now()},
__v: {type: Number, select: false}
}, {strict: true})
export default mongoose.model('Invoice', InvoiceSchema);
And I am not receiving any error, the booking is successful. I tried logging the data received in the then block, and it is a valid document, as I have already mentioned above.
EDIT: The following is the complete code that invovlves the use of generateInvoice function: book.js
Insted of
return Invoice.create(invoiceData).then((data)=>{...
Try
new Invoice(invoiceData).save((err,data)=>{
if(err) return console.log(err);
return data._id;
})

MongoDB/mongoose creating a relation between two models?

I am looking to create a one-to-many relationship following this pattern http://docs.mongodb.org/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/
I have an Exercise.js schema, which will contain a collection of exercises.
var exerciseSchema = new mongoose.Schema({
_id: String,
title: String,
description: String,
video: String,
sets: Number,
reps: String,
rest: Number
});
Then I have a workout plan BeginnerWorkout.js schema
var workoutDaySchema = new mongoose.Schema({
_id: String,
day: Number,
type: String,
exercises: Array
});
I want to associate an array of exercises to the workoutDaySchema, this contains a collection of workout days for a particular workout, each day has a collection of exercises.
I have a seeder function that generates the workout for me.
check: function() {
// builds exercises
Exercise.find({}, function(err, exercises) {
if(exercises.length === 0) {
console.log('there are no beginner exercises, seeding...');
var newExercise = new Exercise({
_id: 'dumbbell_bench_press',
title: 'Dumbbell Bench Press',
description: 'null',
video: 'null',
sets: 3, // needs to be a part of the workout day!!
reps: '12,10,8',
rest: 1
});
newExercise.save(function(err, exercises) {
console.log('successfully inserted new workout exercises: ' + exercises._id);
});
} else {
console.log('found ' + exercises.length + ' existing beginner workout exercises!');
}
});
// builds a beginner workout plan
BeginnerWorkout.find({}, function(err, days) {
if(days.length === 0) {
console.log('there are no beginner workous, seeding...');
var newDay = new BeginnerWorkout({
day: 1,
type: 'Full Body',
exercises: ['dumbbell_bench_press'] // here I want to pass a collection of exercises.
});
newDay.save(function(err, day) {
console.log('successfully inserted new workout day: ' + day._id);
});
} else {
console.log('found ' + days.length + ' existing beginner workout days!');
}
});
}
So my question is inside building a workout plan, how can I associate the exercises into the exercises key using mongoose?
Try this:
exercises: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Exercise', required: false }]
And add an exercise to the workout using the exercise._id (In your code above you'd need to put this in the relevant callback such as the callback for .save on the exercise):
newDay.exercises.push(newExercise._id);
_id is generally a generated number so I don't know if you can set it to the text string you suggest.
When you .find() a workout you'll need to populate the exercises too. Something like:
BeginnerWorkout.find({}).
.populate('exercises')
.exec(function(err, exercises) {
//etc

Create unique autoincrement field with mongoose [duplicate]

This question already has answers here:
Mongoose auto increment
(15 answers)
Closed 2 years ago.
Given a Schema:
var EventSchema = new Schema({
id: {
// ...
},
name: {
type: String
},
});
I want to make id unique and autoincrement. I try to realize mongodb implementation but have problems of understanding how to do it right in mongoose.
My question is: what is the right way to implement autoincrement field in mongoose without using any plugins and so on?
const ModelIncrementSchema = new Schema({
model: { type: String, required: true, index: { unique: true } },
idx: { type: Number, default: 0 }
});
ModelIncrementSchema.statics.getNextId = async function(modelName, callback) {
let incr = await this.findOne({ model: modelName });
if (!incr) incr = await new this({ model: modelName }).save();
incr.idx++;
incr.save();
return incr.idx;
};
const PageSchema = new Schema({
id: { type: Number , default: 0},
title: { type: String },
description: { type: String }
});
PageSchema.pre('save', async function(next) {
if (this.isNew) {
const id = await ModelIncrement.getNextId('Page');
this.id = id; // Incremented
next();
} else {
next();
}
});
Yes, here's the "skinny" on that feature.
You need to have that collection in your mongo database. It acts as concurrent key allocation single record of truth if you want. Mongo's example shows you how to perform an "atomic" operation to get the next key and ensure that even there are concurrent requests you will be guaranteed to have the unique key returned without collisions.
But, mongodb doesn't implement that mechanism natively, they show you how to do it. They only provide for the _id to be used as unique document key. I hope this clarifies your approach.
To expand on the idea, go ahead and add that mongo suggested implementation to your defined Mongoose model and as you already guessed, use it in Pre-save or better yet pre-init event to ensure you always generate an id if you work with a collection server side before you save it to mongo.
You can use this.
This package every time generate unique value for this.
Package Name : uniqid
Link : https://www.npmjs.com/package/uniqid
Ignore all the above. Here is the solution
YourModelname.find().count(function(err, count){
req["body"].yourID= count + 1;
YourModelname.create(req.body, function (err, post) {
if (err) return next(err);
res.json(req.body);
});
});

Resources