Mongodb schema emptied after seconds - node.js

When i am making a request to save a new object to my mongodb, it gets saved, and after seconds everything in that schema disappears.
In the screenshot below you can see this happening, where with the first command i check that the schema is empty, then i make a request to save a new object which is done successfully, and after a few seconds you can see that the object has disappeared.
The express endpoint looks like so:
router.post('/bookdate',passport.authenticate('jwt', {session:false}), (req, res) => {
const userId = req.user._id
const appartmentNumber = req.user.apartmentNumber;
const requestedDate = req.body.requestedDate;
const bookingZone = req.body.bookingZone;
const newBooking = new Booking({
'apartmentNumber': appartmentNumber,
'dateOfBooking': requestedDate,
'bookingZone': bookingZone
});
if (req.user.hasTimeBooked) {
res.json({booked: false, msg: 'There is already a booking for this user.'})
} else {
if (typeof newBooking.requestedDate !== undefined && typeof newBooking.bookingZone !== undefined) {
Booking.addBooking(newBooking, (err, result)=>{
if(err){
res.json({booked: false, msg: err})
} else {
res.json({booked: true, msg: result})
}
})
} else {
res.json({booked: false, msg: 'Undefined parameters Date or Zone'})
}
}
});
and the mongoose schema looks like so
const mongoose = require('mongoose');
const config = require('../config/database');
const BookingSchema = mongoose.Schema({
apartmentNumber:{
type: Number,
unique: true
},
dateOfBooking:{
type: Date
},
bookingZone:{
type: String
}
});
const Booking = module.exports = mongoose.model('bookings',BookingSchema, 'bookings');
module.exports.addBooking = function(bookingObj, cb){
var newBooking = new Booking(bookingObj);
newBooking.save(cb);
}
There are no errors appearing in console, and i am not quite sure where to start looking.
Thanks in advance!
EDIT
The result from db.bookings.getIndices() is shown in the screenshot here

From the getIndices output I could see you've created an TTL index on dateOfBooking so it gets deleted after 60 seconds in the backend
From the mongo docs TTL index
TTL indexes are special single-field indexes that MongoDB can use to
automatically remove documents from a collection after a certain
amount of time or at a specific clock time

Related

Mongoose document _id is null, so when I try to save I get MongooseError: document must have and id before saving

I'm making a discord bot to scrape prices from Amazon. Im using a mongoDB database to store links users give to the bot to track the price of the item the link leads to.
My issue is when I run my code and use the add command, my console reads...
Starting...
Online! Logged in as Amazon Price Tracker#6927
Connected to Database
null
MongooseError: document must have an _id before saving
at C:\Users\logic\Documents\Disc Bot\node_modules\mongoose\lib\model.js:291:18
at processTicksAndRejections (node:internal/process/task_queues:78:11)
Disconnected from Database
I've read the doc's and my understanding is mongoose generates a unique id automatically. I am aware that you can override this my defining an id in your schema, but I haven't done this so I don't know why console.log(a) prints null, and the .save() errors out.
My add.js file
//add function using mongoose for mongodb
const { SlashCommandBuilder } = require("#discordjs/builders");
const mongoose = require("mongoose");
const { MongoDBurl } = require("../config.json");
const Link = require("../Schemas/Link.js");
module.exports = {
//Build the slash command
data: new SlashCommandBuilder()
.setName("add")
.setDescription("add a url to watch list")
.addStringOption(option =>
option.setName("url")
.setDescription("url to add to watch list")
.setRequired(true),
),
//Function that runs when the command is used
async execute (interaction) {
const URL = interaction.options.getString("url");
const user = interaction.user.username;
await interaction.reply(`On it! Adding ${URL} to your watch list`)
//Connect to the database, throws an error if it can't connect
await mongoose.connect(MongoDBurl)
.then( () => console.log("Connected to Database"))
.catch(err => console.log(err));
//Check if the link is already in the database
var exists = await Link.exists({ link: URL}).exec()
.catch(err => console.log(err))
if (exists) {
console.log("This Document Already Exists")
interaction.editReply(`Oops! That link is already in my database.`)
} else {
//If the link dosen't exist, create a document and save it to the database
var newLink = new Link({ user: user }, { link: URL }, { price: "N/A" })
// Debuging variable
var a = newLink.id;
console.log(a)
await newLink.save()
.then( () => {
console.log("Document Saved")
interaction.editReply(`All done! I have saved ${URL} to your watch list.`)
})
.catch(err => {
console.log(err)
interaction.editReply("Oops! Something went wrong, I wasen't able to save this link.")
})
}
//Close the connection when we finish
await mongoose.connection.close()
.then( () => console.log("Disconnected from Database"))
}
};
My Link.js file
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const LinkSchema = new Schema({
user: {
type: String,
requiered: true
},
link: {
type: String,
requiered: true
},
price: {
type: String,
requiered: true
},
})
module.exports = mongoose.model("Link", LinkSchema);
When creating a new modal, the options must be within the same pair of curly braces, however when updating, its separate since you are changing multiple elements.
That's why the error was occurring. You have already shared a working piece of code so I'm guessing you no longer need one.
So I found my issue. I changed this line
var newLink = new Link({ user: user }, { link: URL }, { price: "N/A" })
To
const newLink = new Link({ user: user, link: URL, price: "N/A" });
I don't know why this fixed it, I don't think its because I changed var -> const, and looking at the documentation I thought the first line was the correct way to do this
The line I originally used from the documentation
Tank.updateOne({ size: 'large' }, { name: 'T-90' }, function(err, res) {
// Updated at most one doc, `res.nModified` contains the number
// of docs that MongoDB updated
});
Is this an error in the documentation? or a possible bug? either way the issue is now resolved.

Cannot add property to mongoose document with findOneAndUpdate

My express app tries to record the login time of the user using Mongoose's findOneAndUpdate.
router.post('/login', passport.authenticate('local', {
failureFlash: true,
failureRedirect: '/'
}), async(req, res, next) => {
// if we're at this point in the code, the user has already logged in successfully.
console.log("successful login")
// save login time to database
const result = await User.findOneAndUpdate({ username: req.body.username }, { loginTime: Date.now() }, { new: true });
console.log(result);
return res.redirect('/battle');
})
The user document does not start out with a login time property. I'm expecting this code to insert that property for me.
The actual result is, the console shows the user document being printed out, but without any added login time property. How can I fix this so a login time property is inserted into the document? Is the only way to do it by defining a login time property in the original mongoose schema? And if so, doesn't that nullify the supposed advantage of NoSQL vs SQL in that it's supposed to allow new unexpected property types into your collections and documents?
I've found the answer for anyone who might come across the same problem. It is not at all possible to add a property to a Mongoose collection if it is not already defined in the Schema. So to fix it I added the property in the Schema.
In fact, you can add a new property that isn't defined in the schema, without modifying the schema. You need to set the flag strict to false to enable this mode. See document here.
The code below demonstrates what I said, feel free to runs it:
const mongoose = require('mongoose');
// connect to database
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false });
// define the schema
const kittySchema = new mongoose.Schema({
name: String
// this flag indicate that the shema we defined is not fixed,
// document in database can have some fields that are not defined in the schema
// which is very likely
}, { strict: false });
// compile schema to model
const Kitten = mongoose.model('Kitten', kittySchema);
test();
async function test() {
// empty the database
await Kitten.deleteMany({});
// test data
const dataObject = { name: "Kitty 1" };
const firstKitty = new Kitten(dataObject);
// save in database
await firstKitty.save();
// find the kitty from database
const firstKittyDocument = await Kitten.findOne({ name: "Kitty 1" });
console.log("Mongoose document", firstKittyDocument);
// modify the kitty, add new property doesn't exist in the schema
const firstKittyDocumentModified = await Kitten.findOneAndUpdate(
{ _id: firstKittyDocument._id },
{ $set: { age: 1 } },
{ new: true }
);
console.log("Mongoose document updated", firstKittyDocumentModified);
// note : when we log the attribute that isn't in the schema, it is undefined :)
console.log("Age ", firstKittyDocumentModified.age); // undefined
console.log("Name", firstKittyDocumentModified.name); // defined
// for that, use .toObject() method to convert Mongoose document to javascript object
const firstKittyPOJO = firstKittyDocumentModified.toObject();
console.log("Age ", firstKittyPOJO.age); // defined
console.log("Name", firstKittyPOJO.name); // defined
}
The output:
Mongoose document { _id: 60d1fd0ac3b22b4e3c69d4f2, name: 'Kitty 1', __v: 0 }
Mongoose document updated { _id: 60d1fd0ac3b22b4e3c69d4f2, name: 'Kitty 1', __v: 0, age: 1 }
Age undefined
Name Kitty 1
Age 1
Name Kitty 1

NodeJS 'mongodb' client update function not working sometimes

mongodb client version: 3.1.10
I am using hosted mongo db server on Mlab.com: Shared Production-Ready cluster.
var dbo = db.db(DB);
var collection = dbo.collection('schedule');
var query = {email:userEmail};
let availability = (availabilityArg==="offQ")?"no":"yes";
let note = (availabilityArg==="offQ")?"Off Queue":"";
var data = {available:availability,notes:note};
collection.update(query,{$set:data},function(err,data){
if(err)
console.log("DB find error.");
else{
console.log(userEmail+((availabilityArg==="offQ")?" off the queue":" back in queue"));
}
});
The above works 95% of the time. 5% of the time, the DB does not get updated at all.
95%: The DB get's updated based on the availabilityArg. If it is offQ, the available attribute will be set to no. If it is onQ, the available attribute will be set to yes. The notes attribute also gets updated accordingly.
5%: The DB does not get updated at all. There's no change to the available attribute and the notes attribute. Though I see the console.log statement with the email ID and the off the queue/back in queue message.
It just doesn't make sense.
PS:
function(db,userEmail, availabilityArg)
I took your code and re-imagined it as follows, I hope it helps.
/*
I am not sure what is going on behind here
so I'll just comment it out, and show you
an implementation that works, which you can
repurpose.
*/
// var dbo = db.db(DB);
// var collection = dbo.collection('schedule');
/*
NOTE: Below is the an example model for handling data using mongoose,
This should be in a separate file which you would import
*/
const mongoose = require('mongoose');
const schema = new mongoose.Schema({
email: {
required: true,
type: String,
require: true
},
availability: {
required: true,
type: String,
default: ''
},
notes: {
required: true,
type: String,
default: ''
}
});
// If in the same file (not advisable)
const Schedule = mongoose.model('Schedule', schema, 'schedule_collection');
// Or export (advisable)
module.exports = mongoose.model('Schedule', schema, 'schedule_collection');
// NOTE: Below is a re-imagined version of your code
const findQuery = { email: userEmail };
const availability = availabilityArg === 'offQ' ? 'no' : 'yes';
const notes = availabilityArg === 'offQ' ? 'Off Queue' : '';
// NOTE: For updating the document
const updateQuery = {
availability: availability,
notes: notes
};
// NOTE: Using findOneAndUpdate of the Model
Schedule.findOneAndUpdate(findQuery, updateQuery, (err, _) => {
if (err)
console.log("DB error.");
else {
console.log(userEmail + ((availabilityArg === "offQ") ? " off the queue" : " back in queue"));
}
});

Mongoose find results in empty array and pretty sure all models match up

I am sure this has been answered before but I could not get anything to work.
I have a simple Node.js application that just gets an id and looks up an incident by that id. For now I would like to just get back all incidents no matter their ID.
Below is my code, I have checked and the DB connection string is working correctly (I can see connections when starting my application)
Controller
// Model
const Incident = require('../models/incident');
exports.fetchByID = function(req, res, next) {
console.log(req.params.id);
Incident.find({}, (err, incident) => {
if(err) console.log(err)
if(!incident || incident == []) return res.json({success: false, message: 'No incident found'});
if(incident) return res.json({success: true, incident});
});
};
Model
const mongoose = require('mongoose');
const incidentSchema = new mongoose.Schema({
status: {
type: Boolean,
default: false
},
createdAt: { type: Date, required: true, default: Date.now }
});
module.exports = mongoose.model('Incident', incidentSchema);
How I am connecting
// Mongo Connection
const dbString = `${config.db}/incident`;
mongoose.connect(dbString, { autoReconnect: true, useNewUrlParser: true }, (err) => {
if (!err) console.log('MongoDB has connected successfully.');
});
Name of DB.collection in Mongo Atlas incident.incidents
There is 1 document in the DB currently.
{
"success": true,
"incident": []
}
Okay, so this is weird... I copied the connection string from another application that uses the same DB. The only difference was ?retryWrites=true so I tried adding that to my connection string and it works. I have zero clue why that would matter when I am trying to read not do any writes.
Can anyone explain what happened and why it was saying it connected and everything but returned an empty array instead of the correct value?

Nodejs Duplicate Fields

I'm using a POST route to post data on a user's progress. I'm looking for a way to check if theres duplicate fields when posting, so I don't post multiple results
My route:
api.post('/progress', (req, res) => {
let progress = new Progress();
progress.user_id = req.body.user_id;
progress.level = req.body.level;
progress.save(function (err) {
if (err) {
res.send(err);
}
res.json({
message: 'progress saved!'
});
});
});
My Model
import mongoose from 'mongoose';
let Schema = mongoose.Schema;
let progressSchema = new Schema({
user_id: String,
level: String,
});
var levels = mongoose.model('Progress', progressSchema);
module.exports = mongoose.model('Progress', progressSchema);
Are you using MongoDB? If so, you can use mongoose module and add
unique: true,
to the field's attributes in your Progress schema. Check out the docs. Hope this helps.

Resources