Mongoose check reference id - node.js

I'm a newbie to mongoose and express. Tried to find an answer to my question, but no luck. I have the following schemas:
var Schema = mongoose.Schema;
var Project= new Schema ({
name: {
type: String,
required: true,
min: 5,
max: 255
},
description: {
type: String,
min: 5,
max: 500
},
status: {
type: String,
min: 5,
max: 255
},
priority: {
type: String,
min: 5,
max: 255
},
progress: {
type: String,
min: 5,
max: 255
} ,
_user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
module.exports= mongoose.model('Project', Project);
var Schema = mongoose.Schema;
var IssueSchema= new Schema ({
description: {
type: String,
min: 5,
max: 500,
required: true
},
status: {
type: String,
min: 5,
max: 255,
default: "Open"
},
priority: {
type: String,
min: 5,
max: 255
},
deadline:{
type: Date
},
_project: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Project'
}
});
module.exports= mongoose.model('Issue', IssueSchema);
I'm working on create Issue middleware for the route /projectId/issues and have the code
const bodyParser = require('body-parser');
const Issue = require ('../models/Issue');
var Project = require ('../models/Project');
const { handleError,ErrorHandler } = require('../helpers/error');
exports.createIssue = (req, res,next) => {
Project.findById(req.params.id);
if (req.params.id!= null) {
console.log('Project found');
const {description, deadline, priority, status} = req.body;
var issue = new Issue({
description,
deadline,
status,
priority,
_project:req.params.id
});
issue.save();
res.status(200).send("Issue created!")}
else {
err = new Error('Project ' + req.params.id + ' not found');
err.status = 404;
return next(err);
}
};
And it's not working :( What I'm trying to achieve is to check if projecID exists before saving "issue" document. Any ideas on how to implement this?

Project.findById accepts a callback with parameters error and document
Project.findById(req.params.id, (error, project) => {
console.log(project) // project will be null if not found.
// handle project !== null here
})

You are checking whether or not an id was passed to params:
if (req.params.id!= null)
But this does not tell you whether there is a Project associated with that id. You need to check the return value of Project.findById(req.params.id). Some like:
let result = Project.findById(req.params.id)
if(!result.length) console.log('No project found")
In this case, I'm pretty sure the result variable will be an array however, it may also be an object so console.log(result) and see what you get. Then write you conditional statement based on that.
Also, if you want to catch any errors, you need to use a try/catch block instead of if/else.

Related

How to update deeply nested documents in mongoose v6.2.2

I am trying to update deeply nested documents and confusing myself with all of the nesting. Below is my model and code so far. I want to update 'purchased' value of inventory based on the size variable that is passed in. I was reading about arrayFilters but I still cannot figure it out.
model:
const mongoose = require('mongoose');
const inventorySchema = new mongoose.Schema({
size: {
type: String,
},
purchased: {
type: Number,
},
used: {
type: Number,
},
});
const kidsSchema = new mongoose.Schema({
firstName: {
type: String,
trim: true,
minlength: 1,
maxlength: 99,
},
currentChild: {
type: Boolean,
},
brandPreference: {
type: String,
trim: true,
minlength: 1,
maxlength: 99,
},
currentSize: {
type: String,
},
currentSizeLabel: {
type: String,
},
lowAlert: {
type: String,
},
diaperHistory: [diaperHistorySchema],
totalPurchased: {
type: Number,
},
totalUsed: {
type: Number,
},
inventory: [inventorySchema],
});
const KidsRecordSchema = new mongoose.Schema({
kids: [kidsSchema],
});
const KidsRecord = mongoose.model('KidsRecord', KidsRecordSchema);
exports.KidsRecord = KidsRecord;
code:
/**
* #description PUT add diapers to kids inventory
*/
router.put('/update/:size', auth, async (req, res) => {
let id = req.body.user_id;
let kidID = req.body.kids_id;
let size = req.params.size;
let purchased = req.body.purchased;
try {
let record = await KidsRecord.findOne({ user_id: id });
let subRecord = record.kids.id(kidID);
let inventory = subRecord.inventory.filter((x) => x.size == size);
console.log('inventory', inventory);
// inventory give me:
// [{ "size": "0", "purchased": 0, "used": 0, "_id": "625e91571be23abeadbfbee6"}]
// which is what I want to target but then how do I apply $set to it?
// $set... ??
if (!subRecord) {
res.send({ message: 'No kids for this user.' });
return;
}
res.send(inventory);
} catch (error) {
res.send({ message: error.message });
}
});
I can drill down and find the correct inventory object I want to update, but not sure how to actually change in and save.

Unable to fetch any items from MongoDB database

My connection with the mongodb server gets established but I am unable to fetch any items from there.
This is a simple query to get all items from the User collection.
User.find({}, function (err, result) {
if (err) {
console.log(err);
} else {
res.json(result);
}
});
My User schema is very simple as well:
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
minlength: 5,
maxlength: 35,
},
password: {
type: String,
required: true,
minlength: 5,
maxlength: 100,
},
username: {
type: String,
required: true,
minlength: 5,
maxlength: 20,
},
});
module.exports = {
User: mongoose.model("user", userSchema),
};
What can I do?
Is the User.find() call inside of a route? If not, res.json() will not work. Try console.log ing it.
Spelling mistake on my end. Fixed!

In mongoose set a field based on the value of another field in findOneAndUpdate

I'm working on a project where in one model I need to set the value of a field based on another fields value. Let me explain with some code.
Destination model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const DestinationSchema = new Schema({
name: {
type: String,
required: true
},
priority: {
type: Number,
default: 0,
max: 10,
required: true
}
})
DestinationSchema.statics.getPriority = function(value) {
return this.findOne({ _id: value })
}
const Destination = mongoose.model('Destination', DestinationSchema)
exports.Destination = Destination
Task model
const mongoose = require('mongoose')
const { Destination } = require('../_models/destination.model')
const Schema = mongoose.Schema;
const TaskSchema = new Schema({
priority: {
type: Number,
required: true,
min: 0,
max: 25
},
from: {
type: Schema.Types.ObjectId,
ref: 'Destination',
required: true
},
to: {
type: Schema.Types.ObjectId,
ref: 'Destination',
required: true
},
type: {
type: Number,
required: true,
min: 0,
max: 3
}
}, {
timestamps: true
})
TaskSchema.pre('save', async function () {
this.priority = await Destination.getPriority(this.from).then(doc => {
return doc.priority
})
this.priority += await Destination.getPriority(this.to).then(doc => {
return doc.priority
})
this.priority += this.type
})
Task Controller update function
exports.update = async function (req, res) {
try {
await Task.findOneAndUpdate({
_id: req.task._id
}, { $set: req.body }, {
new: true,
context: 'query'
})
.then(task =>
sendSuccess(res, 201, 'Task updated.')({
task
}),
throwError(500, 'sequelize error')
)
} catch (e) {
sendError(res)(e)
}
}
When I create a new Task, the priority gets set in the pre save hook just fine as expected. But I'm hitting a wall when I need to change Task.from or Task.to to another destination, then I need to recalculate the tasks priority again. I could do it on the client side, but this would lead to a concern where one could just simply send a priority in an update query to the server.
My question here is, how can I calculate the priority of a Task when it gets updated with new values for from and to? Do I have to query for the document which is about to get updated to get a reference to it or is there another cleaner way to do it, since this would lead to one additional hit to the database, and I'm trying to avoid it as much as possible.
In your task schema.
you have to use pre("findOneAndUpdate") mongoose middleware. It allows you to modify the update query before it is executed
Try This code:
TaskSchema.pre('findOneAndUpdate', async function(next) {
if(this._update.from || this._update.to) {
if(this._update.from) {
this._update.priority = await Destination.getPriority(this._update.from).then(doc => {
return doc.priority
});
}
if(this._update.to) {
this._update.priority += await Destination.getPriority(this._update.to).then(doc => {
return doc.priority
});
}
}
next();
});

How to set minimum value great then 0 in mongoose schema?

I think that it was easy question, but I am puzzled.
How Can I add minimum value to mongoose > 0?
var customer = new Schema({
cash: {
type: Number,
minimum: 0
}
});
this code allow 0 value, but I want to do > 0
I know, I can do this
var customer = new Schema({
cash: {
type: Number,
minimum: 0
},
validate: {
validator: function(value) {
return value > 0;
},
message: 'cash need to be > 0'
},
});
*cash is float, and can be very small
But it's too long, Is there an easier way?
You ca specify the min while defining the schema.
var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Too few eggs'],
max: 12
},
bacon: {
type: Number,
required: [true, 'Why no bacon?']
},
drink: {
type: String,
enum: ['Coffee', 'Tea'],
required: function() {
return this.bacon > 3;
}
}
});
var Breakfast = db.model('Breakfast', breakfastSchema);
`
var badBreakfast = new Breakfast({
eggs: 2,
bacon: 0,
drink: 'Milk'
});
var error = badBreakfast.validateSync();
assert.equal(error.errors['eggs'].message,
'Too few eggs');
assert.ok(!error.errors['bacon']);
assert.equal(error.errors['drink'].message,
'`Milk` is not a valid enum value for path `drink`.');
badBreakfast.bacon = 5;
badBreakfast.drink = null;
error = badBreakfast.validateSync();
assert.equal(error.errors['drink'].message, 'Path `drink` is required.');
badBreakfast.bacon = null;
error = badBreakfast.validateSync();
assert.equal(error.errors['bacon'].message, 'Why no bacon?');
http://mongoosejs.com/docs/api.html#schema-number-js
Try this:
var customer = new Schema({
cash: {
type: Number,
min: 1
}
});
I assume you are using mongoose.js?

MEAN Stack - Update route not posting correctly

I have built a mean app but am having an issue with it posting a number value. I'm not sure if it is a mongoose validation error but for some reason mongoose can not upsert the number value but will when it is a string.
Here's the route:
//Edit A Site
router.put('/api/sites/:site_id', function(req, res) {
Site.findById(req.params.site_id, function(err, site) {
if (err) {
res.send(err);
} else {
if(req.body.ip) site.ip = req.body.ip;
if(req.body.domain) site.domain = req.body.domain;
if(req.body.wp) site.wp = req.body.wp;
if(req.body.host_name) site.host_name = req.body.host_name;
if(req.body.hosted) site.hosted = req.body.hosted;
console.log(req.body);
// save the site
site.save(function(err) {
if (err)
res.send(err);
res.json(site);
});
}
});
});
The console.log has the full request body:
{ hosted: 1, host_name: 'sup', wp: 'n/a' }
But this is the mongoose response: Mongoose: sites.update({ _id: ObjectId("57a16c4a7f7e5b7a7e1f5ad1") }, { '$set': { host_name: 'sup', wp: 'n/a' } })
Schema:
// grab the things we need
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// create a schema
var sitesEntrySchema = new Schema({
ip: {
type: String,
required: true,
trim: true
},
domain: {
type: String,
required: true,
trim: true
},
wp: {
type: String,
required: true,
trim: true
},
host_name: {
type: String,
required: true
},
hosted: {
type: Number,
min: 0,
max: 1,
required: true
}
});
// make this available to our users in our Node applications
var Site = mongoose.model('Site', sitesEntrySchema);
module.exports = Site;
EDIT:
I believe I found the solution. When checking for the req.body.hosted, because it is a number it fails. I had to update to check for undefined:
if(req.body.hosted != undefined) site.hosted = req.body.hosted;

Resources