I need to update my model when the data has changed. Sadly, this seems to not work.
const mongoose = require('mongoose');
const moment = require('moment');
const Schema = mongoose.Schema;
const SomeSchema = new Schema({
query: String,
data: Object,
userId: String,
// Date.now() does work. I'm working with existing code.
createdAt: { type: Date, default: moment().format() },
updatedAt: { type: Date, default: moment().format() }
});
// Not sure why I need this 😕
// Have also used 'save' instead of 'updateOne'
SomeSchema.pre('updateOne', function(next) {
this.updated = Date.now();
// this.updatedAt = Date.now() does not work either.
return next();
});
mongoose.model('someModel', SomeSchema);
Actual usage:
const mongoose = require('mongoose');
const Model = mongoose.model('someModel');
// Ideally, I wanted something like "Model.findOrCreate" but... cant see that
const obj = {..};
// Im happy nothing will error here with this.
// Would love to use "findOrCreate" instead.
const data = await Model.updateOne({ ...obj });
// I hate this so much... by hey.
if (data.n === 0) {
// Create
Model.create({...obj}).save
}
All Im saying is, if the data is there, update it and if not, create it. But my updatedAt key is not updating at all. It stays the same as the createdAt. Based on the docs, I dont see how I'd use $set here.
The main thing is to trigger updatedAt whenever the data was found.
Script example using MongoDB Atlas Triggers:
exports = function(changeEvent) {
const { updateDescription, fullDocument, ns } = changeEvent;
const updatedFields = Object.keys(updateDescription.updatedFields);
// For debug
//console.log('changeEvent', JSON.stringify(changeEvent));
const isUpdated = updatedFields.some(field =>
field.match(/updatedAt/)
);
const updatedAt = fullDocument.updatedAt;
// Prevent update again after the update
if (!isUpdated || !updatedAt) {
const { _id } = fullDocument;
console.log(`Triggered! ${ns.db}:${ns.coll}:${_id}, isUpdated:${isUpdated ? 'true' : 'false'}, updatedAt:${updatedAt}`);
const mongodb = context.services.get(ns.db /* Cluster Name, like the DB name */);
const collection = mongodb.db(ns.db).collection(ns.coll);
collection.updateOne({
_id: _id,
}, {
$set: {
updatedAt: new Date(),
}
});
}
};
Looks like there is a typo in the Pre middleware function. Based on our Schema the key name is updatedAt, but in the function, it's mentioned as updated.
Related
I am creating a MERN app and have a series of mongoose schema that are connected.
The hierarchy goes: Program -> Workout -> Exercise -> Set
Here is the model code for each Schema:
Program Schema
const programSchema = mongoose.Schema({
program_name:{
type: String,
},
workouts:[{
type: mongoose.Types.ObjectId,
ref: 'Workout'
}]
Workout Schema
const workoutSchema = mongoose.Schema({
workout_name:{
type:String
},
exercises: [{
type: mongoose.Types.ObjectId,
ref: 'Exercise'
}]
Exercise Schema
const exerciseSchema = mongoose.Schema({
exercise_name:{
type:String
},
notes:{
type:String
},
sets:[{
type: mongoose.Types.ObjectId,
ref: 'Set'
}]
Set Schema
const setSchema = mongoose.Schema({
weight:{
type: String
},
repetitions:{
type: String
},
rpe:{
type: String
}
My question is, now that they are all separate. How do I link a specific Set to a Exercise? or a specific Exercise to a Workout? etc. How do I reference them to each other so that I can create a whole program with various workouts, and each workout having various exercises, etc.
I would appreciate any wisdom. Thank you
For more info, here are the controllers.
Program Controller (CREATE NEW PROGRAM)
const createProgram = async (req, res) => {
//const {program_name, workouts} = req.body
try {
const program = new Program(req.body) // create a new program with the information requested
await program.save() // save it to database
res.status(201).send(program) // send it back to user
} catch (e) {
res.status(500).send(e)
}
WORKOUT CONTROLLER (CREATE NEW WORKOUT)
const createWorkout = async (req, res) => {
const {workout_name} = req.body
try {
const workout = await new Workout({
workout_name
})
await workout.save()
res.status(201).send(workout)
} catch(e) {
}
EXERCISE CONTROLLER (CREATE NEW EXERCISE)
const createExercise = async (req, res) => {
const { exercise_name='', notes='', sets } = req.body
try {
const exercise = await new Exercise({
exercise_name,
notes,
sets
})
await exercise.save()
res.status(201).send(exercise)
} catch (e) {
console.log(e)
}
SET CONTROLLER (CREATE NEW SET)
const createSet = async (req, res) => {
const {repetitions='', weight='', rpe=''} = req.body
try {
const set = await new Set({
weight,
repetitions,
rpe
})
await set.save()
res.status(201).send(set)
} catch (e) {
res.status(500).send(e)
}
The way I do it is on save I add the id to the attributed array. So i'll give you an example for one of your Routers then hopefully you can understand enough to do the rest.
For workouts you want to add it to a program when it's created. so when you create it, just add the id to the program you want to add it to.
Like so:
const {workout_name} = req.body
try {
const newWorkout = await Workout.create({
workout_name
})
Program.updateOne(
{ _id: req.params.ProgramId },
{ $addToSet: { workouts: newWorkout._id }},
)
res.status(201).send(workout)
} catch(e) {
}
So basically after creating your workout, you add that workout ID to the workouts array of the parent object. You would do the same for the rest of your Routers.
I have searched everywhere, StackOverflow and else where but I can't seem to find a fix for my problem. I have a mongoose schema like this:
// user.model.js
const mongoose = require('mongoose');
const User = new Schema({
firstName: String,
lastName: String,
tz: String,
registrationDate: {
type: Date,
default: Date.now(),
}
})
And I have a controller which creates a User like this:
// user.controller.js (async)
let user = await User.create({
'firstName': 'John',
'lastName': 'Doe',
'tz': 'Africa/Kampala'
});
await reply.send(user); // I am using Fastify framework
No matter what I do, when the User is returned it always gives the UTC time and not the time that the User actually is in. have tried using Mongoose transform:
// Transform on the schema
const moment = require('moment-timezone');
const User = new Schema({
// Schema definitions
}, {
toJSON: {
transform: function (doc, ret) {
ret.registrationDate= moment.tz(doc.registrationDate, doc.tz).format();
return ret;
}
}
})
And have also tried using get like this:
const User = new Schema({
// Other definitions
registrationDate: {
type: Date,
default: Date.now(),
get: convertDate
}
})
function convertDate(registrationDate) {
return moment.tz(registrationDate, this.tz).format()
}
But no luck. I would appreciate any assistance or guidance in getting this to work on the model. Thanks!
I can't figure out how to save fetched events from Calendar API. I was able to print out array of events in console. I would require save multiple events at once and have verification if they already exist in database with unique id.
Here's my event.js scheme in express js.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const EventSchema = new Schema({
id: {
type: String,
required: false,
unique:true
},
start: {
type: String
},
end: {
type: String
},
status: {
type: String
},
creator: {
type: Array
},
description: {
type: String
}
});
module.exports = Event = mongoose.model('events', EventSchema);
Here's my event.js router in express js.
router.post("/google/get", async (req, res, next) => {
const {
google
} = require('googleapis')
const {
addWeeks
} = require('date-fns')
const {
OAuth2
} = google.auth
const oAuth2Client = new OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET
)
oAuth2Client.setCredentials({
refresh_token: process.env.GOOGLE_REFRESH_TOKEN,
})
const calendar = google.calendar({
version: 'v3',
auth: oAuth2Client
})
calendar.events.list({
calendarId: 'MY CALENDAR ID',
timeMin: new Date().toISOString(),
timeMax: addWeeks(new Date(), 1).toISOString(),
singleEvents: true,
orderBy: 'startTime',
},
function (err, response) {
if (err) {
console.log("The API returned an error: " + err)
return
}
var events = response.data.items
events.forEach(function (event) {
var start = event.start.dateTime || event.start.date
console.log("%s - %s", start, event.summary)
})
}
)
In Mongoose, in order to save something to a database, all you need to do is to instantiate the model that you created. Your event schema exports Event as a model that you can then treat as a regular object. So you would do something along the lines of:
let currentEvent = new Event({id, start, end, status, creator, description});
currentEvent.save();
Once that is done, it should be stored in your MongoDB. I assume that as the code for this is not visible it is already set up and working. You can just run the above inside of your for loop with some minor tweaks to grab each value correctly and it should sort your issue out!
As for your unique ID and making sure that it doesn't already exist in your database, you can use the same model to find values by checking the id against your database and seeing if it exists. As follows:
Event.findById(id, (err, event) => {
if(event == null) {
let currentEvent = new Event({id, start, end, status, creator, description});
currentEvent.save();
} else {
alert("Error, this event already exists")
}
});
I believe something like this should work, however I might have it wrong with how to check if the event exists, I can't remember if it returns null or something different, so just console log the value of event and check to see what it returns if there isn't an event that exists with that ID, and just re-run your if statement with that instead.
I am trying to fetch all users from a MongoDB database. However for some reason recently the request did not fetch anything.
Here is the code in which I try to fetch the data:
app.get('/api/allusers', (req, res) => {
Employee.find()
.then(rettrievedData => {
res.json(rettrievedData)
});
});
Here is the mongoose model:
const mongoose = require('mongoose');
const employeeSchema = mongoose.Schema({
name: { type: String },
surName: { type: String },
mail: { type: String },
phone: { type: String },
});
module.exports = mongoose.model('Employee', employeeSchema, 'employee.employees');
Here is the code for connecting to Mongo
mongoose.connect("mongodb+srv://Kiril:xxxxxxxxxxxxx#cluster0-owdfy.mongodb.net/employee?retryWrites=true&w=majority")
.then(() => {
console.log("Connected")
})
Also I have checked that there is data in the database, but for some reason the Employee.find() does not retrieve anything. What can be reason?
Thanks in advance.
why you are adding 'employee.employyes' when you creating your model
try to export the model without it
module.exports = mongoose.model('Employee', employeeSchema)
or better
exports.Employee = mongoose.model('Employee', employeeSchema)
and require it where you want to use it
const Employee = require('path to the schema file')
I am bout to add the prelimGrade, midtermGrade, finalsGrade on my overall grade and divide it to 3. This code is giving me null value.
i have tried searching here and found a problem with the solution but the value is also giving me null.
Here is my code on my Test.js schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const TestSchema = new Schema({
prelim: { type: Number, default: 1 },
midterm: { type: Number, default: 1 },
finals: { type: Number, default: 1 },
overall: { type: Number }
});
module.exports = Test = mongoose.model("tests", TestSchema);
TestSchema.pre("save", function(next) {
this.overall = (this.prelim + this.midterm + this.finals)/3;
next();
});
and this is my code on my route
router.post("/test", (req, res) => {
const { prelim, midterm, finals, overall } = req.body;
const test = new Test({
prelim,
midterm,
finals,
overall
});
test.save().then(test => {
res.json(test);
});
});
i expect that it gives me value but it gives me null.
The module.exports should be after the testSchema. This worked for me