How to update an array element in a mongoose db - javascript

I am trying to update the "like" of an array in my mongoose db
{
"_id" : ObjectId("59c7eb0c4a992f8702d847a4"),
"title" : "Favorite Rapper",
"token" : "9b3fd295a1",
"votes" : [
{
"like" : 0,
"vote" : "Kendric"
},
{
"like" : 0,
"vote" : "Jcole"
},
{
"like" : 0,
"vote" : "Kid Cudi"
},
{
"like" : 0,
"vote" : "Kanye"
},
{
"like" : 0,
"vote" : "A$AP Rocky"
}
],
"__v" : 0
}
I would like to find the mongoose db by the id and update the like of which ever element in the "votes" array. .
My question is How do i update my db document by first finding it by the id and then targeting the right element in the votes array to change the like property?
let express = require('express'),
router = express.Router(),
request = require('request'),
rtg = require('random-token-generator'),
db = require('./db');
router.post('/', (req, res) => {
let token = '';
rtg.generateKey({
len: 10, // Generate 16 characters or bytes of data
string: true, // Output keys as a hex string
strong: false, // Use the crypographically secure randomBytes function
retry: true // Retry once on error
}, function(err, key) {
let newVote = {
title: req.body.title,
votes: req.body.categories,
token: key
}; //end of newVote
db(newVote).save();
res.status(200).send(key);
});
}); //end of post
router.get('/:search', (req, res) => {
let search = req.params.search
console.log('votes url hit', search);
db.find({
'token': new RegExp(search, 'i')
}, function(err, vote) {
if (err) {
console.log('err', err);
res.send(500);
} else {
console.log('search was succesful', vote);
res.status(200).send(vote);
}
});
}); //end of get
router.put('/', (req, res) => {
console.log('THIS IS WHERE I WANT TO UPDATE THE DB', req.body);
res.send(200);
}); //end of get
module.exports = router;

You can use findOne to find you doc then save method to update your like.
db.findOne(findQuery, function(err, doc){
if(err) throw err;
doc.votes = doc.votes ? doc.votes : [];
doc.votes.forEach( (data, index, arr){
if(data.vote == "My Vote"){
arr[index]["like"] += 1 // or you new value;
}
});
doc.save();
})

Related

unable to find records in mongobd after await model.save in nodejs/express.js application

I have 2 models employee and tasklist.
var mongoose=require("mongoose");
var findOrCreate = require('mongoose-findorcreate');
var uniqueValidator = require('mongoose-unique-validator');
var employeeSchema = new mongoose.Schema({
empId : { type : Number , unique : true, required : true },
empName : { type : String , unique : true, required : true },
empTeam : { type : String , required : true },
created : {type : Date, default : Date.now}
});
employeeSchema.plugin(findOrCreate,uniqueValidator);
module.exports = mongoose.model("Employee", employeeSchema);
// Mongoose Tasklist Model config
var mongoose=require("mongoose");
var findOrCreate = require('mongoose-findorcreate');
var uniqueValidator = require('mongoose-unique-validator');
var tasklistSchema = new mongoose.Schema({
taskId : { type : Number , unique : true, required : true },
taskDesc : { type : String , unique : true, required : true },
taskDetails : {type : String},
taskAssignee : [{
type:mongoose.Schema.Types.ObjectId,
ref:"Employee"
}],
startDate: Date,
dueDate: Date,
taskStatus: String,
created : {type : Date, default : Date.now},
});
tasklistSchema.plugin(findOrCreate, uniqueValidator);
module.exports = mongoose.model("Tasklist", tasklistSchema);
I have an edit route where I am assigning multiple assignees to the task.
router.post("/tasklist/:id/edit", function(req,res){
Tasklist.findOneAndUpdate({_id:req.params.id},req.body.tasklist, async function(err, tasklist){
if(err){
req.flash("error", "Unable to update the tasklist record : "+err.message);
res.redirect("/employee");
} else {
var emp_id=req.body.taskAssignee.split(',');
try {
emp_id.forEach(assignee => {
return new Promise (function(resolve, reject){
Employee.findById(assignee, function(err, employee){
if(err){
console.log("error in finding employee :"+assignee);
reject("There was an error loading the employee data in to the database : "+err.message);
} else {
tasklist.taskAssignee.push(employee);
console.log("employee saved");
resolve("Employee records uploaded successfully");
}
});
});
});
console.log("Tasklist Saving....")
let savetasklist= await tasklist.save();
console.log("Tasklist Saved : ");
req.flash("success", "Updated Tasklist"+req.body.tasklist);
res.redirect("/tasklist");
} catch (err){
req.flash("error", "Updating Tasklist"+err);
res.redirect("/tasklist");
}
}
});
});
I am able to push the employee to tasklist.taskAssignee and also do a tasklist.save(). There are no errors. However, the update is not persisted in the mongoDB.
The console output looks like this.
some more logging info.
connection successful
Tasklist Saving....
employee saved: Assignee:5ebebe1476911d570448ee44Employee:{
_id: 5ebebe1476911d570448ee44,
empId: 32141,
empName: 'adsdasd',
empTeam: 'C Team',
created: 2020-05-15T16:06:44.342Z,
__v: 0
}
record pushed
Tasklist Saved :
{
taskAssignee: [
{
_id: 5ebebe1476911d570448ee44,
empId: 32141,
empName: 'adsdasd',
empTeam: 'C Team',
created: 2020-05-15T16:06:44.342Z,
__v: 0
}
],
_id: 5ebf1c4830f79c178c7f9905,
taskId: 17562,
taskDesc: 'WTX subscription process',
dueDate: 2020-05-25T18:30:00.000Z,
created: 2020-05-15T22:48:40.091Z,
__v: 0
}
Need help on this. Why is tasklist not getting persisted with employee ?
I look urcode, seems u are not waiting for promise to resolve
const promises = emp_id.map((assignee) => {
return new Promise(function (resolve, reject) {
Employee.findById(assignee, function (err, employee) {
if (err) {
console.log("error in finding employee :" + assignee);
reject(
"There was an error loading the employee data in to the database : " +
err.message
);
} else {
tasklist.taskAssignee.push(employee);
console.log("employee saved");
resolve("Employee records uploaded successfully");
}
});
});
});
await Promise.all(promises) // here wait..
Whole example.
router.post("/tasklist/:id/edit", function (req, res) {
Tasklist.findOneAndUpdate(
{ _id: req.params.id },
req.body.tasklist,
async function (err, tasklist) {
if (err) {
req.flash(
"error",
"Unable to update the tasklist record : " + err.message
);
res.redirect("/employee");
} else {
var emp_id = req.body.taskAssignee.split(",");
try {
const promises = emp_id.map((assignee) => {
return new Promise(function (resolve, reject) {
Employee.findById(assignee, function (err, employee) {
if (err) {
console.log("error in finding employee :" + assignee);
reject(
"There was an error loading the employee data in to the database : " +
err.message
);
} else {
tasklist.taskAssignee.push(employee);
console.log("employee saved");
resolve("Employee records uploaded successfully");
}
});
});
});
await Promise.all(promises)
console.log("Tasklist Saving....");
let savetasklist = await tasklist.save();
console.log("Tasklist Saved : ");
req.flash("success", "Updated Tasklist" + req.body.tasklist);
res.redirect("/tasklist");
} catch (err) {
req.flash("error", "Updating Tasklist" + err);
res.redirect("/tasklist");
}
}
}
);
});

Avoid duplicates when saving new data with mongoose

I am working on an application where I can save destinations to my Mongo DB. I would like to throw a custom error when trying to save a destination that already exsist in the DB. Mongoose prevents that from happening but I want clear and userfriendly error handling.
// post a new destination
router.post('/',
(req, res) => {
const newCity = new cityModel(
{
name: req.body.name,
country: req.body.country
}
)
newCity.save()
.then(city => {
res.send(city)
})
.catch(err => {
res.status(500).send('Server error')
})
});
Before saving a new destination, you can check if there is document already using findOne method, and if it exists you can return a custom error.
router.post("/", async (req, res) => {
const { name, country } = req.body;
try {
const existingDestination = await cityModel.findOne({name,country});
if (existingDestination) {
return res.status(400).send("Destionation already exists");
}
let newCity = new cityModel({ name, country });
newCity = await newCity.save();
res.send(city);
} catch (err) {
console.log(err);
res.status(500).send("Server error");
}
});
Note that I guessed the duplication occurs when the same country and name exist. If it is not what you want, you can change the query in findOne.
Since you've created unique index, When you try to write duplicate then the result would be :
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }"
}
})
Your code :
Constants File :
module.exports = {
DUPLICATE_DESTINATION_MSG: 'Destionation values already exists',
DUPLICATE_DESTINATION_CODE: 4000
}
Code :
//post a new destination
const constants = require('path to constants File');
router.post('/',
(req, res) => {
const newCity = new cityModel(
{
name: req.body.name,
country: req.body.country
}
)
try {
let city = await newCity.save();
res.send(city)
} catch (error) {
if (error.code == 11000) res.status(400).send(`Destination - ${req.body.name} with country ${req.body.country} already exists in system`);
/* In case if your front end reads your error code &
it has it's own set of custom business relates messages then form a response object with code/message & send it.
if (error.code == 11000) {
let respObj = {
code: constants.DUPLICATE_DESTINATION_CODE,
message: constants.DUPLICATE_DESTINATION_MSG
}
res.status(400).send(respObj);
} */
}
res.status(500).send('Server error');
})

Multiple queries in one final custom JSON

I'm trying to create an api route using Node and Express and I must say I don't have much experience with it. Right know I have the following code:
app.get('/api/place/:id', (req, res) => {
var id = req.params.id;
var message_error = '{"status": "failed", "message": "Unable to fetch data"}';
db.query("SELECT `id`, `user`, `lat`, `lon`, `elevation`, `rating`, `rating_count`, `country`, `continent`, `locality` FROM `t_points` WHERE id = ?", [id], (err, res1) => {
if(err) {
res.json(message_error);
} else {
//Store the user id from the points table and use it to fetch user datas
var userId = res1[0].user;
if(userId != null) {
db.query("SELECT `id`, `name` FROM `t_users` WHERE `id` = ?", [userId], (err, res2) => {
if(err) {
res.json(message_error);
} else {
//Final json structure
res.json({
id: res1[0].id,
lat: res1[0].lat,
lon: res1[0].lon,
elevation: res1[0].elevation,
rating: res1[0].rating,
rating_count: res1[0].rating_count,
user: {
id: res2[0].id,
name: res2[0].name
}
});
}
});
} else {
res.json({
id: res1[0].id,
lat: res1[0].lat,
lon: res1[0].lon,
elevation: res1[0].elevation,
rating: res1[0].rating,
rating_count: res1[0].rating_count
});
}
}
});
});
I'm hard-coding the json structure so if the userId in my table is null I don't print the user object in the json, otherwise I print it. But that's not a good idea, as I will also add more queries in the same route. Is there a simple way to create just one json at the end of all the queries and if some values are null not showing it?
Also, would it be better to use async and await functions to do it, instead of this way?
Thanks!
use util maybe better way to get result when querying data.
const mysql = require('mysql');
const util = require('util');
// ? connection pool
let db = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
port: 3306,
user: 'root',
password: 'secretpass',
database: 'yourdatabasename'
});
// ? check connection
db.getConnection((err, connection) => {
if (err) {
console.log('database connection failed');
} else {
console.log('database connection resolved');
connection.release();
}
});
// ? formatter query
function queryString(spName, ...queryParam) {
return mysql.format(spName, queryParam);
}
// ? do query
let performQuery = util.promisify(db.query).bind(db)
module.exports = {
performQuery,
queryString
}
then use the function above like this :
app.get('/api/place/:id', async (req, res) => {
const id = req.params.id;
const message_error = '{"status": "failed", "message": "Unable to fetch data"}';
try {
let prepareOne = queryString(SELECT `id`, `user`, `lat`, `lon`, `elevation`, `rating`, `rating_count`, `country`, `continent`, `locality` FROM `t_points` WHERE id = ?", id);
let resultOne = await performQuery(prepareOne);
let userId = resultOne[0].user;
if (userId != null) {
let prepareTwo = queryString("SELECT `id`, `name` FROM `t_users` WHERE `id` = ?", userId);
let resultTwo = await performQuery(prepareTwo);
res.json({
...resultOne,
user: {
...resultTwo
}
});
}
} catch (err) {
res.send(message_error);
}

embedded insertion of Array in mongodb

I have to try to store array data inside MongoDB using this query below. but every time I run this query its show success message without data means an empty array inside MongoDB,
my requirement is to store array data inside MongoDB as below query.
1). This is my node js script
this.childQuestionInfo = function(req, res, next){
try{
var quizArr = [];
var quizObj = {
'child.quiz.questionId' : req.params.questionId,
'child.quiz.score' : req.params.score,
'child.quiz.time' : new Date().toISOString()
};
quizArr.push(quizObj);
var userObj = {
'userid' : req.params.userId,
'quiz' : quizArr
};
var childinfoSave = new QuizChildInfo(userObj);
childinfoSave.save(function(err, data){
if(err) return next(err);
res.send("Child questionId score and date saved successfully" + data);
console.log("Child questionId score and date saved successfully");
});
}catch(err){
console.log('Error While Saving the child questionId score and Date ' +err);
return next(err);
}
};
2). This is my child schema
userId:{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
quiz:[
{
questionId:{
type: mongoose.Schema.Types.ObjectId,
ref: 'question'
},
score:{type:Number},
time:{type:String}
}
]
3). This is my output screen via postman
"Child questionId score and date saved successfully
{ __v: 0,\n _id: 57b9ac672c5791f8097d2132,\n levelsAttempted: [],\n quiz: [ { _id: 57b9ac672c5791f8097d2133 } ] }"
Try this using $push
this.childQuestionInfo = function(req, res, next){
try{
var queryObj={};
var childObj={};
var queryObj = {userid: req.params.userId};
var options = {safe: true, upsert: true};
childObj.questionId' : req.params.questionId,
childObj.score' : req.params.score,
childObj.time' : new Date().toISOString()
};
QuizChildInfo.findOneAndUpdate( queryObj, { $push: childObj }, options, function (err, data) {
if(err) return next(err);
res.send("Child questionId score and date saved successfully" + data);
console.log("Child questionId score and date saved successfully");
});
}catch(err){
console.log('Error While Saving the child questionId score and Date ' +err);
return next(err);
}
};

NodeJS Mongoose - Cannot call method 'toString' of undefined

I am trying to print out to the console the name of a Team in my database, here is the code:
var Team = require('../schemas/Team').Model;
app.get('/match', function(req, res) {
var key = 1359407087999; // Team Key
Team.findByKey(key, function(err, team) {
util.log(team);
if (err) {
util.log("Error occured");
}
if (!team) {
util.log("The team does not exist");
} else {
res.send("Found team: " + team.name);
}
});
});
The code gets the Team successfully where util.log(team) is. It prints this to the console:
{
__v: 0,
_id: 5106e7ef9afe3a430e000007,
name: 'Team Name',
key: 1359407087999
}
This also works when sending it to the web page as well.
But when I try to send the Team's name to the web page, I get the following output with the res.send method => Found team: undefined...And when I try to output team.name instead of team to the console, I get the error Cannot call method 'toString' of undefined
Here is my Team mongoose schema as well:
var Team = new Schema({
'key' : {
unique : true,
type : Number,
default: getId
},
'name' : { type : String,
validate : [validatePresenceOf, 'Team name is required'],
index : { unique : true }
}
});
Team.statics.findByKey = function(key, cb){
return this.find({'key' : key}, cb);
};
module.exports.Schema = Team;
module.exports.Model = mongoose.model('Team', Team);
show team
app.get('/show/team/:key', function(req, res){
util.log('Serving request for url[GET] ' + req.route.path);
Team.findByKey(req.params.key, function(err, teamData){
util.log(teamData[0]);
if (!err && teamData) {
teamData = teamData[0];
res.json({
'retStatus' : 'success',
'teamData' : teamData
});
} else {
util.log('Error in fetching Team by key : ' + req.params.key);
res.json({
'retStatus' : 'failure',
'msg' : 'Error in fetching Team by key ' + req.params.key
});
}
});
});
Name is unique, so you should use findOne instead of find.
Team.statics.findByKey = function(key, cb){
return this.findOne({'key' : key}, cb);
};

Categories