Save multiple model documents in one POST route with Mongoose/Express/Node - node.js

I have a one-to-many relationship with my Search model and Result model. My user will do a search, select the results that were helpful, and hit a save button. That save button will hit an app.post() request. This should save an instance of the Search and one (or more) instance(s) of the selected Results. I can successfully save the Search instance with the following code:
controllers/searchController.js
const Search = require('../models/search');
exports.search_create_post = (req, res) => {
let newSearch = new Search({ search_text: req.body.search_text });
newSearch.save((err, savedSearch) => {
if (err) {
console.log(err);
} else {
res.send(savedSearch);
}
})
routes/search.js
const express = require('express');
const router = express.Router();
const search_controller = require('../controllers/searchController');
//Search Routes
router.get('/', search_controller.search_home);
router.get('/results', search_controller.search_results_get);
router.post('/', search_controller.search_create_post);
module.exports = router;
How can I make it so that my user hitting the save button once will save the Search instance above and also the Results?

I ended up doing what I needed by passing two callbacks into my post() route and calling next() inside the first one along with passing the data the second one needed through the req object. My code is as follows:
routes/search.js
router.post('/', search_controller.search_create_post, result_controller.result_create_post);
controllers/searchController.js
exports.search_create_post = (req, res, next) => {
let newSearch = new Search({ search_text: req.body.search_text });
newSearch.save((err, savedSearch) => {
if (err) {
console.log(err);
} else {
req.searchData = savedSearch;
}
next();
})
};
controllers/resultController.js
exports.result_create_post = (req,
let newResult = new Result({ url: 'req.body.url', search: req.searchData });
newResult.save((err, savedResult) => {
if (err) {
console.log(err);
} else {
res.send(savedResult);
}
})
};

Related

req.session is not saving data

For now, I'm using the default store for sessions (i.e. not yet saving session data to a DB). I have a POST route that uses a middleware that checks a DB for a user, and if the user is present it saves the user object to the session, this is working fine, then a little further down in that same middleware I add to that same session based on a condition, this second write to the session is not occurring, not even at the completion of the route.
app.post('/', searchDb(db), (req, res) => {
res.redirect(`/someplace`);
});
In a middleware folder ...
searchDB = (db) => {
return async (req, res, next) => {
{ email } = req.body;
const user = await db.findOne({ emailAddress: `${email}` })
if (user) {
req.session.validUser = user;
if (condition) {
req.session.validUser.storeMoreStuff = "something"
} else {
req.session.validUser.storeMoreStuff = "somethingelse"
}
return next();
}
}
}
module.exports = { searchDB };
What am I not understanding?
Update#1: 1/14/22: Although it felt a little hacky, I tried modifying the user object prior to saving it to the session.
searchDB = (db) => {
return async (req, res, next) => {
{ email } = req.body;
let user = await db.findOne({ emailAddress: `${email}` })
if (user) {
user.storeMoreStuff = "something"
req.session.validUser = user;
return next();
}
}
}
module.exports = { searchDB };
However, only the original version of the user object that was pulled from the DB got written to the session.
Update#2: 1/14/22: Tried also to modify a copy of the user object, before saving to the session.
searchDB = (db) => {
return async (req, res, next) => {
{ email } = req.body;
let user = await db.findOne({ emailAddress: `${email}` })
let test = user;
test.storeMoreStuff = "something"
req.session.validUser = test;
}
}
module.exports = { searchDB };
Same result. I'm wondering now if "user", which comes from the DB find operation, is even an object (even though it seems to look like one). Perhaps this is why seemingly normal object operations are not working as expected. Going to add a "mongodb" tag, in case this is a Mongo idiosyncrasy / misunderstanding.
I'm reluctant to call this an answer, because I don't understand why, however, by copying each key-value pair of the user object into a temporary object before making the additional key-value pair assignment I was able to update the object and then write it to the session:
searchDB = (db) => {
return async (req, res, next) => {
{ email } = req.body;
const user = await db.findOne({ emailAddress: `${email}` })
if (user) {
const copyUser = {
key1: user.value1,
key2: user.value2,
key3: user.value3
}
req.session.validUser = copyUser;
if (condition) {
req.session.validUser.storeMoreStuff = "something"
} else {
req.session.validUser.storeMoreStuff = "somethingelse"
}
return next();
}
}
}
module.exports = { searchDB };

sending formdata through POST throws an error at second time

I am making item list that I can add items into a data.json file from input:text.
nodejs will receive POST request and store formdata into data.json.
input:text and submit button are inside form.
I put some text in input:text.
click submit button and addEventListener has e.preventDefault(). so page won't refresh.
nodejs receives POST request then function itemManager will deal with formdata and run writeFile and readFile.
That's my logic but this won't work at second button click.
At second button click, page will show me this picture.
router.js
const express = require('express');
const router = express.Router();
const itemController = require('../controllers/itemController');
router.get('/', itemController);
router.post('/', itemController);
module.exports = router;
itemController.js
const fs = require('fs');
function itemManager(req, res) {
console.log(Object.keys(req.body).length);
if (Object.keys(req.body).length) {
console.log(req.body);
let json = JSON.stringify(req.body);
json = json + "\n";
fs.writeFile('./data/data.json', json, {
encoding: "utf-8",
flag: "a+"
}, (err) => {
if (err) console.log(err);
else {
console.log(`success!`);
}
});
}
fs.readFile('./data/data.json', 'utf8', (err, data) => {
if (err) res.render('index');
else {
const dataArray = data.split('\n');
dataArray.pop();
for (let i in dataArray) {
dataArray.push(JSON.parse(dataArray.shift()));
}
console.log(`data Array!!!!! : `, dataArray);
res.render('index', {dataArray});
}
})
}
module.exports = itemManager;

node.js Why data from post requests that is saved in a json file resets to initial empty array after restart server?

I am working with express node.js, and I am trying to save datas from post request in a json file. but for some reason when I restart the server, my data from post request was supposed to save in roomDB.json file doesnt remain instead it resets to initial empty array...
Could anyone please advice? thank you very much.
here is my code
//saving function
const fs = require("fs");
exports.save =(data, PATH) =>{
return new Promise((resolve, reject) => {
fs.writeFile(PATH, JSON.stringify(data), function(err) {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
// code in router file to make requests
const express = require("express");
const router = express.Router();
const fs = require("fs");
const rooms = ("./roomDB.json");
const { addRoom} = require("./rooms");
router.get("/", (req, res)=>{
fs.readFile("roomDB.json", (err, data)=>{
if(err) return res.status(400);
res.send(roomDB_PATH)
})
});
router.get("/:id", (req, res)=>{
res.send("connect to a room");
});
router.post("/", (req, res)=>{
let roomName = req.body;
if(!roomName.name){
res.status(404);
res.end();
return;
}
let room =addRoom(roomName.name);
res.status(201).send(room)
})
module.exports = router;
*/
const uuid = require("uuid");
let roomdatas;
const {save} = require("./save");
const roomDB_PATH = "roomDB.json";
try {
roomdatas = JSON.parse(fs.readFileSync(roomDB_PATH));
} catch (e) {
roomdatas = []
save(roomdatas, roomDB_PATH);
}
const addRoom = (roomName) => {
roomName = roomName.trim().toLowerCase();
const existingRoom = roomdatas.find((room) => room.name === roomName);
if (existingRoom) {
return { error: 'chatroom has existed' };
}
let room = {
name: roomName,
id: uuid.v4(),
messages: [],
users: [],
created: +new Date()
};
roomdatas.push(room);
save(roomdatas, roomDB_PATH);
return { room };
};
module.exports ={addRoom};
I'm assuming that you are encountering an error with the JSON.parse(fs.readFileSync(roomDB_PATH)); call. This code runs every time your server is started (when you import the file into your router file), and if it encounters an error it is resetting the file to an empty array. Try logging the error to see what is causing it. You're currently completely suppressing the error with no way to tell why it is failing.

How to allow users to add in parameter in api?

How to allow users to add in parameter in api? i.e http://localhost:8080/amk_codes?collada_north=1.361692308&collada_east=103.8527273
I have the following codes:
app.get("/amk_codes", async (req, res) => {
const rows = await readamk_codes();
res.send(JSON.stringify(rows))
})
async function readamk_codes() {
try {
const results = await client.query("select collada_north,collada_south,collada_east from amk_codes");
return results.rows;
}
catch(e){
return [];
}
}
The parameters in url are located in req.query object. In your example you can access to collada_north and collada_south values with req.query.collada_north and req.query.collada_south.
app.get("/amk_codes", async (req, res) => {
var collada_north = req.query.collada_north
var collada_south = req.query.collada_south
const rows = await readamk_codes();
res.send(JSON.stringify(rows))
})
...
Of course you have to check if parameters are present in the request ( they could also be null I think ).

Mongo/Express: How to return all documents in collection if no query params are passed?

I'm trying to return all documents from my Mongo collection if no query parameters are passed. Currently I have 3 optional query parameters that could be passed by the user.
localhost:3000/api/projects
//should return all projects. Currently this is returning []
localhost:3000/api/projects?id=1
//should return projects with id of "1". Working properly.
localhost:3000/api/projects?name=myproject
//should return projects with name of "myproject". Working properly.
localhost:3000/api/projects?created_by=John
//should return projects created by "John". Working properly.
Within my route, I'm trying to determine my request has any query values. If it does not, then I want to return all documents in the collection. As stated above, this is not returning anything.
router.get('/', async (req, res) => {
if (req.query !== '') {
const project = await Projects.find({
$or: [
{ _id: req.query.id },
{ name: req.query.name },
{ created_by: req.query.created_by }]
});
res.json(project);
}
else {
const project = await Projects.find();
res.json(project);
}
});
Try as below:
router.get('/', async (req, res) => {
let searchQuery = {}
if(req.query.id){
searchQuery._id = req.query.id
}
if(req.query.name){
searchQuery.name = req.query.name
}
if(req.query.created_by){
searchQuery.created_by = req.query.created_by
}
const project = await Projects.find(searchQuery);
res.json(project);
});
You can write your api handler like this:
router.get('/', async (req, res)=>{
let options = {...req.query};
try{
const project = await Projects.find(options);
res.json(project);
}catch(e){
console.log(e);
}
});
This will fetch the documents on the basis of your query. If there is no query params req.query will be empty object and hence it will find all documents.
Hope this helps!!
router.get('/', async (req, res) => {
const id = req.query.id || null;
const name = req.query.name || null;
const created_by = req.query.created_by || null;
const query = { id, name, created_by };
const project = await Projects.find(query);
res.json(project);
});
I didn't test it, but I would solve your problem this way.

Resources