I need to Update one record in mongodb? - node.js

router.patch('/edit/:id', async (req, res) => {
try {
let id = req.params.id;
let updateData = req.body;
const result = await Category.updateOne(id,updateData);
if(result) {
res.status(200).send({
result: result
});
}
}
catch (err) {
for (field in ex.errors) {
res.status(500).send(ex.errors[field].message);
}
}
})
This is my code but its not Working data not changed in records when i call this function

Related

Cannot Getting data from url query parameters. from a node rest api

I have this code to make a get, post, put and delete request,
const express = require("express");
const TutorialModel = require("../models/tutorialModel");
const router = express.Router();
router.post("/tutorials", async (req, res) => {
try {
const tutorial = new TutorialModel(req.body);
const createTutorial = await tutorial.save();
res.status(201).send(createTutorial);
} catch (e) {
res.status(400).send(e);
}
});
router.get("/tutorials", async (req, res) => {
try {
const TutorialsData = await TutorialModel.find();
res.status(200).send(TutorialsData);
} catch (e) {
res.status(404).send(e);
}
});
router.get("/tutorials/:id", async (req, res) => {
try {
const _id = req.params.id;
const TutorialData = await TutorialModel.findById(_id);
if (!TutorialData) {
res.status(404).send();
} else {
res.send(TutorialData);
}
} catch (e) {
res.status(500).send(e);
}
});
router.get("/tutorials/:title", async (req, res) => {
try {
const _title = req.params.title;
const TutorialData = await TutorialModel.find({ title: _title });
if (!TutorialData) {
res.status(404).send();
} else {
res.send(TutorialData);
}
} catch (e) {
res.status(500).send(e);
}
});
router.put("/tutorials/:id", async (req, res) => {
try {
const _id = req.params.id;
const updateTutorial = await TutorialModel.findByIdAndUpdate(
_id,
req.body,
{ new: true }
);
res.send(updateTutorial);
} catch (e) {
res.status(400).send(e);
}
});
// Deleting student data by its Id
router.delete("/tutorials/:id", async (req, res) => {
try {
const _id = req.params.id;
const deleteTutorial = await TutorialModel.findByIdAndDelete(_id);
if (!_id) {
return res.status(400).send();
} else {
res.send(deleteTutorial);
}
} catch (e) {
res.status(500).send(e);
}
});
router.delete("/tutorials", async (req, res) => {
try {
const deleteTutorial = await TutorialModel.remove();
if (!deleteTutorial) {
return res.status(400).send();
}
else {
res.send(deleteTutorial);
}
} catch (e) {
res.status(500).send(e);
}
});
module.exports = router;
I've successfully made all request including get request with 'id' But when I try to make get request using 'title' parameter I'm getting data of get request of "/tutorials" not of "tutorials/:title". What is the issue? Can anyone tell me please?
The route GET "/tutorials/:id" will catch all your GET requests like /tutorials/something. It does not distinguish if you pass an id or a title.
:id is used to tell Express to capture the something path in the URL in req.params.id. That's all.
If you want to have another route to get tutorials by title, you should use another form. For example, GET "/tutorialsByTitle/:title".

problem in sending base64 data in GET request

Hi I am facing issues sending base64 data in GET request.
I was successful in converting the image into base64 data and inserting it in receivedFile
but during response the attachments come as an empty array while the rest of the data i.e user_id is flowing successfully.
Hence if you could please help me to resolve this issue.
Below is the code
router.js
router.get('/users/data/expand/:nid',async (req,res) => {
var idselected = req.params.nid;
var dir = '\images';
var receivedFile = [];
try {
const checkData = await user.find({"user_id": idselected});
await checkData[0].attachments.forEach (element => {
fs.readdir(dir,function(err,files) {
if(err) {
console.log(err)
}else {
files.forEach((filename) => {
filename = element;
fs.readFile(filename,'base64', (err,base64Data) => {
if(err) {
console.log(err);
}
receivedFile.push(base64Data);
})
})
}
})
})
//issue is here the attachments is coming as empty instead of base64 data
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
})
res.status(201).send(returnUser);
}
catch(e) {
res.status(500).send(e)
}
})
Well its always good to create helper functions and to promisfy it so you can use async / await syntax.
I have changed your code. I didnt tested it but i guess it should work:#
router.get("/users/data/expand/:nid", async (req, res) => {
var idselected = req.params.nid;
var dir = "images";
try {
const checkData = await user.findOne({ user_id: idselected });
let receivedFile = await Promise.all(
checkData.attachments.flatMap(async element => {
let files = await readDirectory(dir);
return await Promise.all(
files.map(filename => {
filename = element;
return readFile(filename)
})
);
})
);
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
});
let savedUser = await returnUser.save();
res.status(201).send(savedUser);
} catch (e) {
res.status(500).send(e);
}
});
function readDirectory(dir) {
return new Promise((res, rej) => {
fs.readdir(dir, function(err, files) {
if (err) {
rej(err);
} else {
res(files);
}
});
});
}
function readFile(filename) {
return new Promise((res, rej) => {
fs.readFile(filename, "base64", (err, base64Data) => {
if (err) {
rej(err);
}
res(base64Data);
});
});
}
I guess you use mongoose.
There is an method called findOne and also you forgot to save your model with returnUser.save()

Nested queries, promises on nodejs

Im trying to build a rest api, fetching a nested mysql queries.
When i fetch the first query, this return a array, then with this array i need to fetch data with another query for each value through a array.map
when the script running, always log a empty array, i think must be cause of promises. any help please?
//this the mysql queries
const getTournaments = 'SELECT ID FROM wp_posts WHERE post_type = "tournament"'
const getTournamentGame = 'SELECT meta_value FROM wp_postmeta WHERE meta_key = "tournament_game" AND post_id = ?'
async function fetchType(id){
return new Promise ((res, rej) => {
try{
pool.query(getTournamentGame, [id], (err, rows) => {
if (err) {
return rej(err)
}else {
return res(rows[0].meta_value)
}
})
} catch(err){
console.log(err)
}
})
}
async function mapeado(array) {
return new Promise (async (resolve,rej) => {
try{
var arr = []
array.map((item) => {
fetchType(item.ID).then((res) => {
var tourData = {
id: item.ID,
type: res
}
return tourData
}).then((data) => {
arr.push(data)
})
})
return resolve(arr)
} catch(err) {
console.log(err)
}
})
}
//making rest api
app.get('/tournaments', async (req, res) => {
pool.query(getTournaments, (err, rows) => {
mapeado(rows).then(console.log)
})
})

Display all collections in mongodb+express

This is my code for sending data to a database:
app.post('/thanks', function(req, res) {
if (atendees.checkin === req.body.dbstring) {
dbConn.then(client => {
delete req.body._id;
const db = client.db('mydata')
db.collection(atendees.checkin).insertOne(req.body);
})
(...)
This is how I display on the page after clicking on a href link:
app.get('/view-feedbacks', function(req, res) {
dbConn.then(client => {
const db = client.db('mydata')
db.collection(atendees.checkin).find({}).toArray().then(function(feedbacks) {
res.status(200).json(feedbacks);
atendees.checkin = ' '
}).catch(err => {
throw(err);
})
});
});
That works fine. How can I do something similar to display all collections from the database instead of just the individual ones?
This is what I tried to do:
app.get('/view-history', function(req, res) {
dbConn.then(client => {
const db = client.db('mydata')
db.listCollections().toArray().then(function(collInfos) {
res.status(200).json(collInfos);
atendees.checkin = ' '
}).catch(err => {
throw(err);
})
});
});
But it just gives me the name of each collection. I want to show all collections and all of their elements.
Edit: my question is different from this one: MongoDB Show all contents from all collections .I'm trying to do this on express.js, not on the terminal
Edit2: Using db.collection:
app.get('/view-history', function(req, res) {
dbConn.then(client => {
const db = client.db('mydata')
db.collections().then(function(feedbacks) {
res.status(200).json(feedbacks);
atendees.checkin = ' '
}).catch(err => {
throw(err);
})
});
But this gives the error: TypeError: converting circular structure to JSON
With async/await, this could be done:
app.get('/view-history', async (req, res) => {
try {
const client = await dbConn;
const db = client.db('mydata');
let collections = await db.collections();
let documents = await Promise.all(collections.map(async (collection) => {
let documents = await collection.find({}).toArray();
return Promise.resolve([collection.collectionName, documents]); // Retain collectionName
}));
// Format into an object that looks like `collectionName: documents`
let formatted = documents.reduce((obj, collection) => {
obj[collection[0]] = collection[1];
return obj;
}, {});
res.json(formatted);
} catch (e) {
console.error(e);
res.sendStatus(500);
}
});
A Promise-only approach:
app.get('/view-history', (req, res) => {
dbConn.then((client) => {
const db = client.db('mydata');
return db.collections();
}).then((collections) => {
return Promise.all(collections.map((collection) => {
return new Promise((resolve, reject) => {
collection.find({}).toArray().then((documents) => {
resolve([collection.collectionName, documents]);
}).catch(reject);
});
}));
}).then((documents) => {
let formatted = documents.reduce((obj, collection) => {
obj[collection[0]] = collection[1];
return obj;
}, {});
res.json(formatted);
}).catch((e) => {
console.error(e);
res.sendStatus(500);
});
});
The main reason this code is unnecessarily verbose is because instead of just returning a big array filled with arrays of documents, you probably want an object that retains the name of the collection, like so:
{
collection1: [...documents...],
collection2: [...documents...],
...
}
Instead of:
[
[...documents...],
[...documents...],
...
]
If you do want just a big array of each collection without caring about the names of the collections, it becomes much simpler:
async/await version:
app.get('/view-history', async (req, res) => {
try {
const client = await dbConn;
const db = client.db('mydata');
let collections = await db.collections();
let documents = await Promise.all(collections.map((collection) => collection.find({}).toArray()));
res.json(documents);
} catch (e) {
console.error(e);
res.sendStatus(500);
}
});
Promise-only version:
app.get('/view-history', (req, res) => {
dbConn.then((client) => {
const db = client.db('mydata');
return db.collections();
}).then((collections) => {
return Promise.all(collections.map((collection) => collection.find({}).toArray()));
}).then((documents) => {
res.json(documents);
}).catch((e) => {
console.error(e);
res.sendStatus(500);
});
});
Have you tried just db.collections()? If that also doesn't give what you need, you might have to invoke db.collection(<name>) on each of the names you get from listCollections.

How to perform forloop in node js

Acoording to the data available ui should get 2 reults but getting only one since i put res.send in the looop so it is getting ended ,can anyone help me out please.......
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return
}
if (resp) {
console.log(resp);
} else {}
});
}
res.send(resp);
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
}
The problem is in getting the profiles. You are using mongodb's find which is asynchronous. Therefore in your for cycle you start fetching the profiles, but then you send out the res.send well before the fetching of the profiles is finished.
The call back from profile.find(... will be executed after the res.send. Apart from this, the resp variable is inside the find callback and you are trying to res.send it outside.
To deal with this, either you use async or promises. See the below code that uses promises.
var Promise = require('bluebird')
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
var profiles_to_get = []
var profiles = []
for (var i in result) {
var id = result[i].recieved_id;
profiles_to_get.push(get_profile(id, profiles))
}
Promise.all(profiles_to_get)
.then(() => {
res.send(profiles);
})
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
function get_profile (id, profiles) {
return new Promise(function (resolve, reject) {
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
reject(err)
return
}
if (resp) {
profiles.push(resp)
resolve()
} else {
reject()
}
});
})
}
}
How this works is that it creates a list of profiles to find and stores it in the var profiles_to_get = []. The you use Promise.All(profiles_to_get) which will let you do stuff after all the profiles have been fetched.
You can send only one response back to a request.
Define a variable outside the for loop, append records to it and then send it after the for loop has ended.
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
var resList = [];
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return
}
if (resp) {
console.log(resp);
resList[i] = resp;
}
else{
}
});
}
}//end of if loop
else {
resList = {
status: 'fail',
data: []
};
}
res.send(resList);
});
Don't use for loop in asynchronous mode. Use async module instead like below.
var async = require('async');
exports.getrequestsdetails = function (req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray(function (err, result) {
if (err) {
return
}
if (result) {
var list = [];
async.each(result, function (item, cb) {
var id = item.recieved_id;
var profile = db.collection('profile');
profile.findOne({
'_id': new ObjectId(id)
}, function (err, resp) {
if (err) {
return cb();
}
if (resp) {
list.push(resp);
console.log(resp);
return cb();
}
return cb();
});
}, function (err) {
res.send(list);
});
}//end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
}
You can push all the resp in list array and send after completing loop.
Like this:
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params);
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
};
record.find(item).toArray((err, result) => {
if (err) {
return err;
}
if (result) {
var list = [];
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return err;
}
else{
list.push(resp);
console.log(resp);
if(i===result[result.length-1]){
res.send(list);
}
}
});
}
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
};
Hope this work for you
You can add all the list in to an array and finally send the data after the loop

Resources