Handling arrays with express post request - node.js

I'm using express to make the API for my web app. Below is the Schema for my annual budgets collection.
var {mongoose} = require('../db/mongoose');
var budgets = new mongoose.Schema({
year: Number,
categories: [{
name: String,
amount: Number
}]
});
var Budgets = mongoose.model('Budgets', budgets);
module.exports = {
Budgets
};
I am trying to passing in an array of categories using postman in the following way:
{
"year":2018,
"categories": [{
"name":"Logistics",
"amount":1500
}, {
"name":"Finance",
"amount":23030
}]
}
This the post request for my this collection. The request times out and is not saved in the database. I cannot seem to figure out what is wrong with the request. Please help
app.post('/annualBudgets', (req, res) => {
var categories = req.body.categories;
var budgets = new Budgets({
year : req.body.year,
});
budgets.categories.push(categories);
budgets.save().then((docs) => {
res.send(docs);
console.log(docs)
}).catch((e) => res.status(404));
});

The problem is here
budgets.categories.push(categories);
it should be
budgets.categories = categories;
// Alternatively
// budgets.categories.push(...categories);
because categories is already an array.

Related

How I can post Request Body array to MongoDb using Nodejs and Mongoose

I am trying the following things:
1 Getting request body (Which is embedded with an Array).
2 Then After getting the request body I am trying to save all the objects in the array into my key of schema called "ExtraInfo".But When I run the API My "ExtraInfo" key has only object id without data.
I have Explained my whole question with my code and in my API Code, I have mentioned my logic with a comment where I am trying to push my array data to my "ExtraInfo" key.
Model:
const mongoose = require('mongoose');
const ExtraInfoModel = mongoose.Schema({
title:String,
body:String,
date: Date
})
const EmbeddedDataModel = mongoose.Schema({
class:Number,
ExtraInfo:[ExtraInfoModel],
})
module.exports = mongoose.model('EmbeddedDataCluster',EmbeddedDataModel);
RequestBody:
{
"class":"96",
"ExtraInfo":[
{
"title":"new1",
"body":"dummy1"
},
{
"title":"new2",
"body":"dummy2"
},
{
"title":"new3",
"body":"dummy3"
},
{
"title":"new4",
"body":"dummy4"
},
{
"title":"new5",
"body":"dummy5"
}
]
}
Now My Api
Router.post('/Embed', async (req, res) => {
const _ExtraInfo = await req.body.ExtraInfo;
console.log(_ExtraInfo);
try {
const _EmbeddedDataModel = await new EmbeddedDataModel({
class: req.body.class,
ExtraInfo:{$push:{$in:_ExtraInfo}}//Here is trying to loop through
//each object from array and trying to push in Key But when the Data
// saved the "ExtraInfo" key is empty and only have object id
});
_EmbeddedDataModel.save();
console.log(_EmbeddedDataModel);
res.json(_EmbeddedDataModel);
} catch (error) {
console.log(error);
res.json(error);
}
})
Result of DB:
{
"_id": "601a1f0e9fcda33570f9e26b",
"class": 96,
"ExtraInfo": [
{
"_id": "601a1f0e9fcda33570f9e26c"
}
]
}
Please Help me

How to add ID of one mongoose collection to an array in another collection?

I'm trying to add the ID of my category documents to my budget documents. Below is the Schema for my budgets.
var {mongoose} = require('../db/mongoose');
var budgetsSchema = new mongoose.Schema({
year: Number,
categoryIDs: [{type:mongoose.Schema.ObjectId,
ref: 'categories'}]
});
var Budgets = mongoose.model('Budgets', budgetsSchema);
module.exports = {
Budgets
};
And here is the Schema for my categories collection.
var {mongoose} = require('../db/mongoose');
var categorySchema = mongoose.Schema({
name: String,
amount: Number,
sub_categories: [{
name: String,
amount: Number
}]
})
var categories = mongoose.model('categories', categorySchema);
module.exports = {
categories
};
To post categories, I use this express post request to add the categories to the category collection and its ID to the Budget collection.
//The ID is the Budget ID
app.post('/categories/:id', (req, res) => {
var id = req.params.id;
var sub_categories = req.body.sub_categories;
var category = new categories({
name: req.body.name,
amount: req.body.amount,
sub_categories
})
category.save().then((docs) => {
res.send(docs);
console.log(docs)
}).catch((e) => res.status(404).send(e));
Budgets.findById(id).then((docs) => {
if(!docs) {
res.status(404).send();
}
docs.categoryIDs.push(category._id);
}).catch((e) => {
res.send(e).status(404);
})
})
When I run this, it does add the category to the collection, but it does not add the ID to the categoryIDs array in the Budget document. Please help
First, change the model name from Plural to Singular as mentioned in the mongoose docs to avoid confusion:
The first argument is the singular name of the collection your model
is for. Mongoose automatically looks for the plural version of your
model name. Thus, for the example above, the model Tank is for the
tanks collection in the database. The .model() function makes a copy
of schema. Make sure that you've added everything you want to schema
before calling .model()!
So categories to Category and Budgets to Budget. Please verify the new before mongoose.model here, Mongoose docs ref.
var categorySchema = new mongoose.Schema({
name: String,
amount: Number,
sub_categories: [{
name: String,
amount: Number
}]
})

How can I sort and limit with Mongoose

I made an review app with Express and Mongoose. I have an review model like below:
var mongoose = require('mongoose');
var ReviewSchema = mongoose.Schema({
title: String,
description: String,
rating: Number
}, {
timestamps: true
}
);
module.exports = mongoose.model('Review', ReviewSchema);
In my controller I just get all reviews list as below. But now I want to get a list with 10 recently reviews & sort by (orderby timestamps). How can I do it with mongoose? Please help me! I am a newbie with NodeJS and Mongodb.
exports.findAll = function(req, res) {
console.log("Fetching Review...")
// Retrieve and return all reviews from the database.
Review.find(function(err, reviews){
if(err) {
console.log(err);
res.status(500).send({message: "Some error occurred while retrieving Review."});
} else {
res.send(reviews);
}
});
};
Thanks you so much
This should work for you:
Review.find()
.sort({_id: -1})
.limit(10)
.then(reviews => {
console.log(reviews)
});
you can try like this :
Review.find({}, function(err,reviews){}).sort({_id: -1}).limit(10);

Mongoose: $inc not working

I am not sure what the problem is, as I've read numerous examples.
Taken from what I was advised here in this StackOverFlow(Mongoose - Increment a value inside an array of objects), I changed the format of poll at ease to accommodate what was recommended.
So I was able to create a document format as so:
{
"_id": "584c4160b3b22e1bdad59bce",
"title": "Food",
"description": "test",
"labelOptions": {
"burger": 29,
"coffee": 44,
"pizza": 23
},
"date": "Dec 10, 2016",
"__v": 0
}
Here's what I have so far:
Poll Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const pollData = new Schema({
title: String,
description: String,
labelOptions: {},
date: String
})
module.exports = mongoose.model('PollData', pollData)
Using express and mongoose, here's what I have:
app.put('/polls/:id', function(req, res){
let id = req.params.id;
let labelOption = req.query.labelOption;
let query = `labelOptions.${labelOption}`
Poll.findByIdAndUpdate(
id,
{$inc: { query: 1 } },
function(err, document){
console.log(err)
console.log(document)
}
)
})
In my terminal, I see that console.log(document it receives the document I was looking for but it does not update the value at all.
Am I setting up the Model correctly? Or does Mongoose does not support template strings?
***update
This is snippet of how I am creating documents
let labelOptions = {}; <=== creating object literal to hold as placeholder
const title = req.body.title;
const description = req.body.description;
req.body.labelOptions.split(/,\s*/).map( prop =>{
labelOptions[prop] = 0 // set counter to default 0
})
const poll = new Poll({
title: title,
description: description,
labelOptions: labelOptions,
date: moment().format('MMM D, YYYY')
});
poll.save(function(err) {
if (err) { return next(err); }
res.json({ message : 'Poll added!'})
});
After doing some research across the internet, I found the reason why it wasnt working: You can't initialize objects with 'dynamic' keys.
Source: Mongoose update on a string variable not working?
By knowing that, it was just a simple solution to initialize an literal object as so:
let id = req.params.id;
let labelOption = req.query.labelOption;
let query = "labelOptions." + labelOption
let obj = {
[query] : 1
}
Poll.findByIdAndUpdate(
id,
{$inc: obj },
function(err, document){
console.log(err)
console.log(document)
}
)

Mongoose saving for populate

I'm new to Mongoose and Nodejs developement in general and I've got a bit of confusion around how to properly set up saving my records. Here are my two schemas:
Download
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var downloadSchema = Schema({
title : String,
description : String,
_project : { type: Schema.Types.ObjectId, ref: 'Project' }
});
module.exports = mongoose.model('Download', downloadSchema);
Project
...
var projectSchema = Schema({
name : String,
url : String,
pwd : String,
_downloads : [{type: Schema.Types.ObjectId, ref: 'Download' }]
});
module.exports = mongoose.model('Project', projectSchema);
This appears to be working correctly. The documentation explains my use-case of saving a download and linking a project, but I'm not sure how to properly populate the Project._downloads. Here's what I've done:
Express route handler:
function createDownload(req, res) {
// the Project Id is passed in the req.body as ._project
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
var dload = new Download(dldata);
dload.save( function (err, download) {
project._downloads.push(download._id);
project.save( function(err){
var msg = {};
if(err) {
msg.status = 'error';
msg.text = err;
}else {
msg.status = 'success';
msg.text = 'Download created successfully!';
}
res.json(msg);
});
});
});
}
This seems overcomplicated to me. Am I supposed to be manually pushing to the ._downloads array, or is that something Mongoose is supposed to handle internally based on the schema? Is there a better way to achieve it so that I can do:
Download.find().populate('_project').exec( ...
as well as:
Project.findOne({_id : _projectId}).populate('_downloads').exec( ...
According to the mongoose docs there are 2 ways to add subdocs to the parent object:
1) by using the push() method
2) by using the create() method
So I think that your code can be a bit simplified by eliminating the operation of saving a new Download item:
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.push(dldata);
project.save(function(err) {
// handle the result
});
});
}
or
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.create(dldata);
project.save(function(err) {
// handle the result
});
});
}

Resources