I'm using node (express) and want to add a new property before my response (in here I named it as result) get passed to the front-end.
async.parallel(stack, function (err,result) {
result.users[0].price = 100
// console.log(result.users[0]); // I couldn't find price property here I wonder why.
res.json(result);
});
Why is this so?
I tried to alter the other property like password:
console.log(delete result.users[0].password);
console.log(result.users[0]) // password is still present here?
I tried a mini example in fiddle it worked. https://jsfiddle.net/16333z15/
router.get('/json', function (req, res) {
var result = {
users: [{
id: 1,
name: "abc"
}]
};
result.users[0].price = 100;
res.json(result);
});
I have tried this in express and it's worked. You should check the result type, I think it's not tuple.
Related
question is possibly a duplicate but I haven't found anything that provides an appropriate answer to my issue.
I have an ExpressJS server which is used to provide API requests to retrieve data from a MongoDB database. I am using mongoosejs for the MongoDB connection to query/save data.
I am building a route that will allow me to find all data that matches some user input but I am having trouble when doing the query. I have spent a long while looking online for someone with a similar issue but coming up blank.
I will leave example of the code I have at the minute below.
code for route
// -- return matched data (GET)
router.get('/match', async (req, res) => {
const style_data = req.query.style; // grab url param for style scores ** this comes in as a string **
const character_data = req.query.character; // grab url param for character scores ** this comes in as a string **
// run matcher systems
const style_matches = style_match(style_data);
res.send({
response: 200,
data: style_matches
}); // return data
});
code for the query
// ---(Build the finder)
const fetch_matches_using = async function(body, richness, smoke, sweetness) {
return await WhiskyModel.find({
'attributes.body': body,
'attributes.richness': richness,
'attributes.smoke': smoke,
'attributes.sweetness': sweetness
});
}
// ---(Start match function)---
const style_match = async function (scores_as_string) {
// ---(extract data)---
const body = scores_as_string[0];
const richness = scores_as_string[1];
const smoke = scores_as_string[2];
const sweetness = scores_as_string[3];
const matched = [];
// ---(initialise variables)---
let match_count = matched.length;
let first_run; // -> exact matches
let second_run; // -> +- 1
let third_run; // -> +- 2
let fourth_run; // -> +- 3
// ---(begin db find loop)---
first_run = fetch_matches_using(body, richness, smoke, sweetness).then((result) => {return result});
matched.push(first_run);
// ---(return final data)---
return matched
}
example of db object
{
_id: mongoid,
meta-data: {
pagemd:{some data},
name: whiskyname
age: whiskyage,
price: price
},
attributes: {
body: "3",
richness: "3",
smoke: "0",
sweetness: "3",
some other data ...
}
}
When I hit the route in postman the JSON data looks like:
{
response: 200,
data: {}
}
and when I console.log() out matched from within the style match function after I have pushed the it prints [ Promise(pending) ] which I don't understand.
if I console.log() the result from within the .then() I get an empty array.
I have tried using the populate() method after running the find which does technically work, but instead of only returning data that matches it returns every entry in the collection so I think I am doing something wrong there, but I also don't see why I would need to use the .populate() function to access the nested object.
Am I doing something totally wrong here?
I should also mention that the route and the matching functions are in different files just to try and keep things simple.
Thanks for any answers.
just posting an answer as I seem to have fixed this.
Issue was with my .find() function, needed to pass in the items to search by and then also a call back within the function to return error/data. I'll leave the changed code below.
new function
const fetch_matches_using = async function(body, richness, smoke, sweetness) {
const data = await WhiskyModel.find({
'attributes.body': body,
'attributes.richness': richness,
'attributes.smoke': smoke,
'attributes.sweetness': sweetness
}, (error, data) => { // new ¬
if (error) {
return error;
}
if (data) {
console.log(data)
return data
}
});
return data; //new
}
There is still an issue with sending the found results back to the route but this is a different issue I believe. If its connected I'll edit this answer with the fix for that.
Well I have the following doubt. I have the following:
JSON
[
{"name": "juan", "age": 10}
{"name": "pedro", "age": 15}
{"name": "diego", "age": 9}
]
User Schema
_group:{
type: mongoose.Schema.Types.ObjectId,
ref: 'Group'
},
name: {
type: String
},
age: {
type: Number
}
And I need to save or update this data in different docs with nodejs/mongoose. I planned to do the following
var data = JSON.parse(json)
for (var i = data.length - 1; i >= 0; i--) {
var name = data[i].name;
var age = data[i].age;
User.find({'name': par, '_group': group_id}, (err, user)=>{
if(err)
next(err);
// if it does not exist, create new doc
if(_.isEmpty(doc)){
var newuser = new User;
newuser.name = name;
newuser.age = age;
newuser.save((err, saved)=>{
})
}// if it exists, update it
else if(!_.isEmpty(doc)){
user.age = age;
user.save((err, saved)=>{
})
}
})
}
as you will see, the variables age and name within User.find remain undefined, so this does not work for me.
First of all, is it the right way to save this data? If so, how could I can use the for cycle variables (name and age) within User.find? If not, what do you recommend me to do?
Thanks,
Eduardo
NodeJS, ExpressJS, Mongoose
There is one more issue which I think you are facing that you are calling a method inside a loop and it takes a call-back, so it doesn't wait here for coming back and move to second iteration, so you might face undefined and some un-expected behavior.
I suggest you should use async/await
let user = await User.findOneAndUpdate({'name': par, '_group': group_id}, { name, age }, { upsert: true })
If you parsed given JSON well and assigned values to name and age, they are not undefined within User.find scope.
Did you checked those variables?
var name = data[i].name;
var age = data[i].age;
You can use mongoose findOneAndUpdate with the option { upsert: true }.
This tries to update an object in the DB and, if the object is not found, it creates it. So:
for (var i = data.length - 1; i >= 0; i--) {
var name = data[i].name;
var age = data[i].age;
User.findOneAndUpdate({'name': par, '_group': group_id}, { name, age }, { upsert: true, new: true, lean: true }, (err, updated) => {
if(err) console.log(err);
else console.log(updated);
})
}
The option new tells to return the updated object and the option lean tells to return a plain JSON, instead of Mongoose document object (the same as calling doc.toJson())
Using the upsert option, you can use findOneAndUpdate() as a find-and-upsert operation. An upsert behaves like a normal findOneAndUpdate() if it finds a document that matches filter. But, if no document matches filter, MongoDB will insert one by combining filter and update as shown below.
data.forEach( user => {
User.findOneAndUpdate({'name': user.name , '_group': group_id}, user , {upsert: true, new: true}, (err, data) => {
if(err) console.log(err);
console.log(data);
})
})
I have a document in my mongoDB
I pass the object from my frontend (user should type something in input filed, for example he types 'test':
{'countdown': 'test'}
And then I pass it to my backend and want to check if he typed right
app.post('/answ', function(req, res) {
var query = req.body;
Model.find(query
, function(err, result) {
if (err) throw err;
if (result) {
if(result.length!== 0) {
res.json('ok');
} else {
res.json('not found');
}
} else {
res.send(JSON.stringify({
error : 'Error'
}))
}
})
});
So, if key-value pair exist, backend will return ok, otherwise not found.
It works for such simple object, but if I try to pass something like:
{'apilisttask': { 'port': '1', 'host': '2', 'path': '3', 'query': '4' } }
In this example user has 4 input fields, I gather all answers and pass it to the backend, but it doesn't give me ok even if the answers are right.
Could you please advice maybe a better approach to compare the data or how to fix the second comparison?
Since you are trying to find in an embedded document, you can not query embedded doc like that.
To query embedded doc, you need to do something like this:
Model.find({'apilisttask.port':query.apilisttask.port, 'apilisttask.host':query.apilisttask.host, ...}, function(err, result){
// ---
});
This should do the trick.
When I do a search with "findOneAndUpdate" and one of my search parameters is "undefined" I do not get an error but is the object searched. this is the code:
var q = Q.defer();
var findOneQuery = {
_id: restId,
versionId: document.version // if this parameter is undefined
};
this.findOneAndUpdate(findOneQuery, {$set: document, $inc: {versionId: 1}}, {upsert: true, new: true}, function (updateError, updateDocument) {
if (updateError) {
q.reject(updateError);
}
else {
q.resolve(updateDocument);
}
});
return q.promise;
I think it should return an error if I'm wrong What should I do to search for the two parameters sent and not just by one of them?
You can easily write a wrapper method around findOneandUpdate that would precisely do what you want with your reqs.
function myFindOneAndUpdate(monObj,query,update,options,callback){
//validateINput check if the params in query object are undefined
if(validateInput(query)){
monObj.findOneAndUpdate(query,update,options,callback)
}else{
throw new Error('InvalidInput');
}
}
If parameter is undefined, then mongodb try to find records in which parameter is undefined. So it would not throw any error.
if you want that versionId should be never null/undefined. then you can validate inputs before passing to db query.
You can use this module:
https://www.npmjs.com/package/validator
I'm new to NodeJS and I am expirimenting with MongoDB. However I have an error which is in my eyes pretty weird: TypeError: Cannot call method 'find' of undefined. I'm trying to use the 'find' method from the node mongo module, collection.find({id: "1"}, callback) but all I get is that error. However, the strange thing is that an insert does work. What is the problem?
db.collection('users', function(error, collection)
{
console.log('Collection:');
// ================ THIS WORKS =================
// insert :
// collection.insert({
// id: "1",
// name: "Marciano",
// email: "email#email.nl",
// }, function()
// {
// console.log('inserted!');
// });
// collection.insert({
// id: "2",
// name: "Edward Elric",
// email: "edward_elric#live.nl",
// }, function()
// {
// console.log('inserted!')
// });
// ======= THIS DOESNT WORK ========
// select:
// specify an object with a key for a 'where' clause
collection.find({'id': '1'}, function(error, cursor)
{
//cursor : iterateing over results
cursor(function(error, user)
{
console.log("found:" + user);
})
})
});
That is not how you iterate a Cursor object returned from .find(). Use the .each() or .toArray() methods in order to deal with results instead.
collection.find({ "id": 1 }).toArray(function(err,data) {
// data is an array of objects from the collection
});
It is caused beucase you insert record to database and dont wait for callback. If you want to do this sequentualy, I suggest you to use async and method waterfall.
But anyway it would be better to use Mongoose instead that you are using now.
and write something like this
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/collection');
var user = new User({ name: 'John' });
user.save(getInsertedUsers);
var getInsertedUsers = function(){
User.find({ name: "John" }, echoUsers); //if you want to get just users named john or
User.find({}, echoUsers);
}
var echoUsers = function(users)
{
console.log(users);
}