Trying to increment by 1 every time the page is viewed - javascript

I'm trying to figure out how to update the field by incrementing +1 each time the page is visited and if it has never been visited then add it to the DB.
Currently, this is what I have got but it does not seem to do much. I must have gone wrong somewhere and I have not yet implemented the part where if the page has never been viewed then create a new object in the array which is stored in the database.
Little note: Where I created the map they do match with the same ID if I view the page with the same ID as the one stored in the database but no increment happens.
exports.pageVisitCount = (req, res, next) => {
User.findById({
_id: req.userData.userId
}, 'visits', function (err, pageVists) {
if (err) {
res.status(401).json({
message: "Error Occured!"
})
} else {
const pageCounts = pageVists.visits;
pageCounts.map(page => {
const postViewed = req.body.postId;
if (page.postId.toString() === postViewed) {
User.findByIdAndUpdate({
_id: req.userData.userId
}, {
$set: {
visits: [{
"postId": postViewed,
$inc: { visitCount: 1 }
}]
}
}, {
upsert: false
},
(err) => {
if (err) {
res.status(401).json({
message: "Error Occured!"
})
} else {
res.status(200).json({
message: "Update successful!"
})
}
});
}
});
}
});
}
This is the schema I am using:
const visitsSchema = new Schema ({
postId: {
type: String
},
visitCount: {
type: Number
}
})
const userSchema = mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
role: {
type: String,
required: true
},
answers: {
type: String
},
visits: [visitsSchema]
});
Any feedback would be highly appreciated, I would like to mention that I am new to backend, thanks!

To avoid using the map to filter the visits after querying the visits of the user under consideration, I suggest you let mongodb do that for you. In this case you first do a find based on both the user id and the postId. If you get a record matching both criteria you are sure you can easily update the user visits by incrementing the particular visits visitCount by 1.
Otherwise i.e. if they don't match any records then since u might be using a valid user id then such user has not visited such post. So you now create a new visit with the postId and initialize its visitCount to 1 (Although we intend to create, but since its a subdocument you'll need use $push). Enough of the talking try the code below.
exports.pageVisitCount = (req, res, next) => {
User.findOne({
_id: req.userData.userId, "visits.postId": req.body.postId
}, 'visits.$', function (err, user) {
if (err) {
res.status(401).json({
message: "Error Occured!"
});
} else {
if(user == null){
User.findByIdAndUpdate({
_id: req.userData.userId
}, {
$push: {
visits: {
"postId": req.body.postId,
visitCount: 1
}
}
}, function (err) {
if(err)
return res.status(401).json({
message: "Error Occured when creating new visit!"
})
return res.status(200).json({
message: "Success"
})
})
}
User.update({
_id: req.userData.userId, "visits.postId": req.body.postId
}, {
$inc: { "visits.$.visitCount": 1 }
},(err) => {
if (err) {
res.status(401).json({
message: "Error Occured!"
})
} else {
res.status(200).json({
message: "Update successful!"
})
}
});
}
});
};

Related

Can't Understand code execution order Javascript

I am learning mongoose and I'm unable to understand some code execution order of javascript
Code:
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/fruitsDB");
const fruitSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "Please check your data entry, no name specified!"],
},
rating: {
type: Number,
min: 1,
max: 10,
},
review: String,
});
const Fruit = mongoose.model("Fruit", fruitSchema);
// Reading data from database
Fruit.find((err, fruits) => {
if (err) {
console.log(err);
} else {
// console.log(fruits);
mongoose.connection.close();
fruits.forEach((fruit) => {
console.log(fruit.name);
});
}
});
// Updating data in database
Fruit.updateOne({ name: "Kiwi" }, { name: "Peach" }, (err) => {
if (err) {
console.log(err);
}
else {
console.log("Successfully updated data");
}
});
// Deleting data in database
Fruit.deleteOne({ name: 'Peach' }, (err) => {
if (err) {
console.log(err);
}
else {
console.log('Data deleted successfully');
}
})
console.log output:
I am unable to understand why the Update function in running before the find() function, can anyone explain this to me please?

Remove document with references Mongoose

I'm having trouble removing Question when Survey gets deleted which is referenced in the Survey model. The survey gets deleted, but the question still remains in the database.
Survey Schema:
let surveyModel = mongoose.Schema(
{
Title: String,
Type: [String],
Questions: { type: mongoose.Schema.Types.ObjectId, ref: "questions" },
Answered: { type: Number, default: 0 }, // how many times users answered
DateCreated: { type: Date, default: Date.now }, // date created
Lifetime: { type: Date, default: Date.now }, // Survey expiry
User: { type: mongoose.Schema.Types.ObjectId, ref: "users" }
},
{
collection: "surveys",
}
);
Question Schema:
let questionModel = mongoose.Schema(
{
MC: {
QuestionText: String,
Options: [String],
},
TF: {
QuestionText: String,
Options: Boolean,
}
},
{
collection: "questions",
}
);
module.exports = mongoose.model("Question", questionModel);
Code I have right now:
// process survey delete
module.exports.processDeletion = (req, res, next) => {
let id = req.params.id;
Survey.remove({ _id: id }, (err) => {
Question.remove({_id: { $in: req.body.Questions }}, (err, res) => {
if (err) {
console.log(err);
res.end(err);
}
});
if (err) {
console.log(err);
res.end(err);
} else {
// refresh survey list
res.redirect("/live-surveys");
}
});
};
Your first step should be delete childrens, that is Question.
Note: i think "Questions" should be more of 1, then it must be an array of Reference in the Survey model. But, for this example it will to be as you have setted.
Then, your delete route, may to be some as:
router.delete("/delete/:surveyById", deleteSurvey");
router.param("surveyById", surveyId"); //This one is your middleware
//surveyController.js
const Survey = require("../models/Survey");
const Question = require("../models/Question");
exports.surveyId = (req, res, next, id) => {
Survey.findById(id).exec((err, data) => {
if(!data || err) return res.status(400).json({error: "Survey not found")};
else {
req.survey = data;
next();
}
)};
};
exports.deleteSurvey = (req, res) => {
Questions.findByIdAndRemove(req.survey.Questions) //Here your Questions Id
.exec((err, data)) => {
if(err) return res.status(400).json({error: "Error to delete questions"});
Survey.findByIdAndRemove(req.survey._id).exec((err, data) => {
if(err) return res.status(400).json({error: "Error to delete Survey"});
return res.json({ message: "Deleted")};
});
});
};
Also you can do with async await if you prefer, is the same, and you will have a better control about your code.

MongoDB/Mongoose $pull an Object in an Array where _id of the Object is matching

I have this Schema here
Consider the likedTours which is an Array of Objects (Tours) (ignore position 0).
I want to pull any Objects where the _id of a Tour matches the critiria.
Adding a new Tour upon liking a tour is okay, but on unlike I don't know how to pull that item out.
Here is my function in the Controller in the Node.JS backend
const unlikeTour = async (req, res) => {
try {
TourDB.Tour.findOneAndUpdate(
{ _id: req.params.tourid },
{
$pull: { likedUsers: req.userID },
$inc: { likes: -1 },
}
).exec(async (err, docs) => {
if (!err) {
try {
await UserDB.User.findOneAndUpdate(
{ _id: req.userID },
{ $pull: { 'likedTours._id': docs._id } } //Here I need help
).exec()
return res.status(200).send({ successMessage: 'Tour successfully unliked' })
} catch (err) {
return res.status(500).send({ errorMessage: 'User not found' })
}
} else {
return res.status(500).send({ errorMessage: 'Tour not found' })
}
})
} catch (err) {
return res.status(500).send({ errorMessage: err })
}
}
This method looks for a tour and update it by pulling out the userID and decrement the likes count by -1.
And then I try to find in the UserDB that tour in the likedTours and tried to pull but it doesn't not work like that.
Thanks in advance
you can update as
await UserDB.User.findOneAndUpdate(
{ _id: req.userID },
{ $pull: { likedTours: { _id: docs._id } } } //Here I need help
).exec();
reference: https://docs.mongodb.com/manual/reference/operator/update/pull/

How to call `findOne` function in an array which is stored in a collection in Mongoose?

The model of the collection is
const clientInfo = {
uniqueID: {
type: String,
required: true,
},
firstName: {
type: String,
required: true,
},
lastName: String,
email: {
type: String,
required: true,
},
countryCode: String,
phone: String,
status: {
type: String,
required: true,
},
addedOn: {
date: String,
time: String,
},
};
And this model is stored in another model
const userClient = {
userID: {
type: String,
required: true,
},
clients: [clientInfo],
};
Now, I want to compare the email of the client with the request body i have received.
I am currently doing it like this:
await UserClient.findOne(
{ userID: validUser.userID },
async (err, clientList) => {
if (clientList) {
//Check for duplicate client
await clientList.findOne(
{ email: req.body.email },
(err, duplicateClient) => {
if (duplicateClient) {
return res.status(400).send(`Client already exists!`);
} else {
clientList.clients.push(client);
clientList.save();
const response = {
statusCode: 200,
message: "Client added!",
client: client,
};
res.send(response);
}
}
);
} else {
const newList = new UserClient({
userID: validUser.userID,
clients: client,
});
newList.save();
const response = {
statusCode: 200,
message: "Client added!",
client: client,
};
res.send(response);
}
}
);
});
But I am getting an error UnhandledPromiseRejectionWarning: TypeError: clientList.findOne is not a function.
What I am doing now is, finding a collection with a specific userID, and If I hot a match, i want to compare all the objects inside the array with the email, i have received on my request body.
Currently, If It does not find any match in the UserClient.findOne, everything goes well, but if I have match in UserFind.findOne and i want to call the similar method in the array, I am getting the error.
How to do I get rid of this error?
Thanks in advance.
Try this
await UserClient.findOne(
{ userID: validUser.userID,'clients.email': req.body.email },
async (err, clientList) => {
if(err){
//throw error here
}
console.log(clientList)
})
Corrected some issues,
find user by id, check if user is found then find client on the base of email in loop if found then return client exists otherwise save to User document,
if client not found then add new user and client
await UserClient.findOne(
{ userID: validUser.userID },
async (err, User) => {
// FIND CLIENT
if (User) {
let clientExists = false;
for (let c in User.clients) {
if (User.clients[c].email == req.body.email ) clientExists = true;
}
// ADD CLIENT
if (clientExists) {
User.clients.push(client);
User.save();
return res.send({
statusCode: 200,
message: "Client added!",
client: client,
});
}
// CLIENT EXISTS
else {
return res.status(400).send(`Client already exists!`);
}
}
// ADD NEW USER AND CLIENTS
else {
const newList = new UserClient({
userID: validUser.userID,
clients: client,
});
await newList.save();
return res.send({
statusCode: 200,
message: "Client added!",
client: client
});
}
}
);
I have not tested this code, let me know if you are getting any issues.

Mongoose validation system element in array not being deleted

I'm currently working on a validation system using Node, Express and Mongoose and have stumbled into a bit of problem. In my Schema I have a verificationId associated with the user so that when they click the link emailed to them it can check to see if that verificationId is the same as the one in the database. All of that works fine, but I can't figure out how to delete the verificationId now that it's no longer needed.
Currently it's validating the user but not deleting verificationId. I've tried messing with the $pull method but I haven't had any success with it. Any help would be appreciated!
//User verification page
app.get("/verify/users/:verifiedId", (req, res) => {
const verifiedId = req.params.verifiedId;
//Check to see if the verificationHash the user was sent is the same as the one stored for them in the database
User.findOne({ verificationHash: verifiedId }, (err, result) => {
if (!err) {
console.log(verifiedId);
console.log(result);
const originalValue = { isVerified: false };
const newValue = { isVerified: true };
//Verify the user in the database
User.findOneAndUpdate(originalValue, newValue, (err) => {
if (!err) {
if (newValue) {
res.redirect("/success");
} else {
res.send(
"There was an error verifying your account. Please try again."
);
}
} else {
res.send(500, { error: err });
}
});
} else {
res.send(err);
console.log(err);
console.log(verifiedId);
}
//Delete the verificationHash from the user in the database
User.findOneAndUpdate(
{ verificationHash: verifiedId },
{ $pull: { verificationHash: { verificationHash: verifiedId } } },
{ new: true }
) });
});
I'm not very sure about this answer but try using the unset operator:
User.findOneAndUpdate(
{ verificationHash: verifiedId },
{ { $unset: {"verificationHash": ""} },
{ new: true }
)
or this may work ( setting the value to null )
User.findOneAndUpdate(
{ verificationHash: verifiedId },
{ verificationHash: null },
{ new: true }
)

Categories