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?
Related
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.
want to fetch all users but just return list of _ids , checked the saved data in db everything seems good.
this is the user model
let UserSchema = new mongoose.Schema({
firstName: {
type: String,
minlength: 3,
trim: true,
},
lastName: {
type: String,
minlength: 3,
trim: true,
},
biography: {
type: String,
minlength: 5,
trim: true,
},
});
UserSchema.methods.toJSON = function () {
let user = this;
let userObject = user.toObject();
return _.pick(userObject, ["_id", "firstName", "email"]);
};
and this is my controller function
const controller = {
fetchUsers :async (_req, res) => {
try {
await User.find({})
.then((users) => {
res.status(200).send(users);
})
.catch((err) => {
res.status(400).send(err);
});
} catch (error) {
res.status(400).json({
Error: `something is wrong. ${error}`,
});
}
}
}
the result is that i tested in postman is :
[
{
"_id": "5fe26ba0d290a216c0fe6d5d"
},
{
"_id": "5fe26c8e40ca9a06b8c96259"
},
]
Don't use .then & await both . Try this once. Assuming model is correct.
const controller = {
fetchUsers :async (_req, res) => {
try {
const users=await User.find({}).exec()
if(users){
res.status(200).send(users);
}
else{
res.status(404).send("no user found");
};
} catch (error) {
res.status(500).json({
Error: `something is wrong. ${error}`,
});
}
}
}
problem is UserSchema.methods.toJSON method there isn't any email field, if we want to filter our output data it's better to filter it by mongoose.find({"condition"},{"fields"})
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!"
})
}
});
}
});
};
I have created a function that is looking for any reservation document with matching _id, if exists is deleted, and next the Book(findById) function is performed which is looking for any books using function(findOneAndUpdate), if exists is added value to quantity +1.But i don't know why but the function does not want to be done.
router.post('/cancel-reservation', (req, res) => {
var reservation = req.body.reservation;
Reservation.findByIdAndRemove(reservation._id, function (err) {
if (err) throw err;
else {
Book.findById(reservation.idBook, (err, book) => {
if (err) throw err;
if (book == null) {
//////////// //*WORKING *////////////////
let bookObj = {
name: reservation.nameBook,
description: reservation.description,
publishingHouse: reservation.publishingHouse,
quantity: 1,
year: reservation.year,
sites: reservation.sites
};
var book = new Book(bookObj);
book.save()
.then(function (book) {
res.json(book)
})
.catch((err) => {
res.json('not saved')
})
//////////// //*WORKING *////////////////
} else if (book) {
// findOneAndUpdate
//////////// //*HERE IS PROBLEM *////////////////
book.quantity = book.quantity+1;
console.log(book._id)
Book.findOneAndUpdate({ _id: book._id },
{ $set: { quantity : book.quantity } }, { upsert: true }),
((err, complete) => {
if(err) console.log('errrrrr');
else {
console.log(complete)
console.log('complete')
res.json(complete)
}
})
}
});
}
});
});
this problem may be related to the fact that the findOneAndUpdate function is nested in findById?
I think that you have an extra parentheses on the findOneAndUpdate
Book.findOneAndUpdate({ _id: book._id },
{ $set: { quantity : book.quantity } }, { upsert: true },
(err, complete) => {
if(err) console.log('errrrrr');
else {
console.log(complete)
console.log('complete')
res.json(complete)
}
})
I am following the FULL STACK JAVASCRIPT DEVELOPMENT WITH MEAN by Adam Bretz & Colin J. Ihrig. When I got to chapter 8 I could not get past this error when trying to insert into an online mongo database. Do I need to use an older version of node? I've looked through stack exchange and have not been able to make it work following all of the suggested fixes...
Here is my error:
TypeError: Cannot read property '_id' of undefined
at insertEmployees (/Users/kikocarisse/Desktop/NODESITES/chapter8/index.js:100:17)
at /Users/kikocarisse/Desktop/NODESITES/chapter8/index.js:195:5
at /Users/kikocarisse/Desktop/NODESITES/chapter8/index.js:79:7
at Function.<anonymous> (/Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/lib/model.js:3369:16)
at /Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/lib/model.js:1890:18
at /Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/async/internal/parallel.js:35:9
at /Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/async/node_modules/lodash/before.js:31:21
at iteratorCallback (/Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/async/eachOf.js:52:13)
at /Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/async/internal/onlyOnce.js:12:16
at /Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/async/internal/parallel.js:32:13
at apply (/Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/async/node_modules/lodash/_apply.js:15:25)
at /Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/async/node_modules/lodash/_overRest.js:32:12
at model.callbackWrapper (/Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/lib/model.js:1865:11)
at next_ (/Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/hooks-fixed/hooks.js:89:34)
at fnWrapper (/Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/node_modules/hooks-fixed/hooks.js:186:8)
at /Users/kikocarisse/Desktop/NODESITES/chapter8/node_modules/mongoose/lib/model.js:3369:16
and here is my code:
"use strict";
var a = require('./a.js');
var b = new a(5);
var mongoose = require('./node_modules/mongoose');
var express = require('express');
var app = express();
var bodyParser = require('./node_modules/body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));
app.route('/echo')
.all((req,res)=>{
let pars = (Object.keys(req.body).length > 0)?req.body:req.query;
res.send(pars);
});
var Schema = mongoose.Schema;
var db = mongoose.connection;
var dbUrl = 'mongodb://*****:******#******:*****/****';
var TeamSchema = new Schema({
name: {
type: String,
required: true
}
});
var Team = mongoose.model('Team', TeamSchema);
var EmployeeSchema = new Schema({
name: {
first: {
type: String,
required: true
},
last: {
type: String,
required: true
}
},
team: {
type: Schema.Types.ObjectId,
ref: 'Team'
},
image: {
type: String,
default: 'images/user.png'
},
address: {
lines: {
type: [String]
},
postal: {
type: String
}
}
});
var Employee = mongoose.model('Employee', EmployeeSchema);
db.on('error', function () {
console.log('there was an error communicating with the database');
});
function insertTeams (callback) {
Team.create([{
name: 'Product Development'
}, {
name: 'Dev Ops'
}, {
name: 'Accounting'
}], function (error, pd, devops, acct) {
if (error) {
return callback(error);
} else {
console.info('teams successfully added')
callback(null, pd, devops, acct);
}
});
}
function insertEmployees (pd, devops, acct, callback) {
Employee.create([{
name: {
first: 'John',
last: 'Adams'
},
team: pd._id,
address: {
lines: ['2 Lincoln Memorial Cir NW'],
postal: '20037'
}
}, {
name: {
first: 'Thomas',
last: 'Jefferson'
},
team: devops._id,
address: {
lines: ['1600 Pennsylvania Avenue', 'White House'],
postal: '20500'
}
}, {
name: {
first: 'James',
last: 'Madison'
},
team: acct._id,
address: {
lines: ['2 15th St NW', 'PO Box 8675309'],
postal: '20007'
}
}, {
name: {
first: 'James',
last: 'Monroe'
},
team: acct._id,
address: {
lines: ['1850 West Basin Dr SW', 'Suite 210'],
postal: '20242'
}
}], function (error, johnadams) {
if (error) {
return callback(error);
} else {
console.info('employees successfully added');
callback(null, {
team: pd,
employee: johnadams
});
}
})
}
function retrieveEmployee (data, callback) {
Employee.findOne({
_id: data.employee._id
}).populate('team').exec(function (error, result) {
if (error) {
return callback (error);
} else {
console.log('*** Single Employee Result ***');
console.dir(result);
callback(null, data);
}
});
}
function retrieveEmployees (data, callback) {
Employee.find({
'name.first': /J/i
}, function (error, results) {
if (error) {
return callback(error);
} else {
console.log('*** Multiple Employees Result ***')
console.dir(results);
callback(null, data);
}
});
}
function updateEmployee (first, last, data, callback) {
console.log('*** Changing names ***');
console.dir(data.employee);
var employee = data.employee;
employee.name.first = first;
employee.name.last = last
employee.save(function (error, result) {
if (error) {
return callback(error);
} else {
console.log('*** Changed name to Andrew Jackson ***');
console.log(result);
callback(null, data);
}
});
}
mongoose.connect(dbUrl, function (err) {
if (err) {
return console.log('there was a problem connecting to the database!' + err);
}
console.log('connected!');
insertTeams(function (err, pd, devops, acct) {
if (err) {
return console.log(err)
}
insertEmployees(pd, devops, acct, function (err, result) {
retrieveEmployee(result, function (err, result) {
retrieveEmployees(result, function (err, result) {
updateEmployee('Andrew', 'Jackson', result, function (err, result) {
if (err) {
console.error(err);
} else {
console.info('database activity complete')
}
db.close();
process.exit();
});
});
});
});
});
});
On line 100, the devops variable is undefined and that's why you're getting your error. See that on insertTeams function is where you will first get your devops value when creating the teams.
This is probably why there your create callback is like: function (error, pd, devops, acct) but seeing Mongoose docs, it pass an array as the second argument of create.
Try this:
function insertTeams (callback) {
Team.create([{
name: 'Product Development'
}, {
name: 'Dev Ops'
}, {
name: 'Accounting'
}], function (error, teams) {
if (error) {
console.log(error);
return callback(error);
} else {
console.info('teams successfully added')
callback(null, teams[0], teams[1], teams[2]);
}
});
}
Notice that now it gets an array and apss it's elements to the callback, also notice that I've added a log, if there is an error you are able to see where it happened.
Also, it'd help if you read the error logs and pointed what are the line contents where the error happens, see that we don't have the line numbers here and it makes it more difficult to find the errors.