Find data with no key value - node.js

So I want to search for items in my database using mongoose .find() function.
In my router I have this code to get certain items from the url.
For example;
mydomainname.com/market?type=1&name=hi&stats=123
...?type=123&name=&...
var type = req.query.type;
var name= req.query.name;
var stats= req.query.stats;
Model.find({type: type, name: name, stats: stats})
.exec(function(err, model){
if(err){
console.log("error")
}else{
res.render('*jade*', {models: JSON.stringify(model)})
}})
This works fine, but when there is no query value in the url(as seen above) the query value will be set to ''. Which then sorts away every item I have on my database because there is none with exmaple name = '';
I have search around but I have not find any help so if any would be able to give me tip I would be grateful!

You could create your find() query object based on the value of the request query parameters. The following example checks for the name field if it has an empty string value, remove the property from the query and then use the final query object as your find() filter:
var q = req.query;
if (q.name === '') {
delete q.name;
}
// carry out further checks
Model.find(q)
.exec(function(err, model){
if(err){
console.log("error");
}else{
res.render('*jade*', {models: JSON.stringify(model)});
}
})

Try this
var q = req.query;
var data ={};
if (q.name !=null) {
data.name = q.name;
}
else if (q.type !=null){
data.type = q.type;
}
else if (q.stats !=null){
data.stats = q.stats;
}
else{
data={};
}
Model.find(data)
.exec(function(err, model){
if(err){
console.log("error");
}else{
res.render('*jade*', {models: JSON.stringify(model)});
}
})

Related

Get count of items that matches a condition from mongo db in node js

I am new to mongo db. I have a scenario where I need to check into collection and the count of items having gameDate = current date.
I am using the following query in node js.
const count = this.games.find({gameDate:currentDate}).count();
console.log(count + "items present")
I have 1 matching record in database. But instead of getting count am getting the following error in console.
function(filter, callback) {
this.op = 'count';
if (typeof filter === 'function') {
callback = filter;
filter = undefined;
}
filter = utils.toObject(filter);
if (mquery.canMerge(filter)) {
this.merge(filter);
}
if (!callback) {
return this;
}
this.exec(callback);
return this;
}
How can I get the count here.
You can try the countDocuments function.
games.countDocuments({gameDate:currentDate}, function (err, count) {
if (err){
console.log(err)
}else{
console.log("Total:", count)
}
});

async.each table insertion trouble?

I wrote a code using async.each for inserting data into tables.
var categoryList = [{"categoryName": "biriyani","productName":"chicken biriyani"}, {"categoryName":"biriyani","productName":"mutton biriyani"}]
async.each(categoryList, function(item,callback)
{
var categoryName=item.categoryName;
var productName=item.productName;
var categoryCheckQuery = pgFormat("select * from shop where categoryName LIKE '%"+categoryName+"%'");
model.client.query(categoryCheckQuery,function (err,result) {
if(result.rowCount==0){
var insertCategoryQuery = pgFormat("insert into shop(categoryName)values(%L)",categoryName);
model.client.query(insertCategoryQuery,function (err,result) {
if (!err) {
console.log("success");
}
});
}
else{
//insert product into product table
}
});
Explanation:
1)Here first Json array containing categoryName->biriyani is entered into shop table
2)when async.each fetching next json array containing categoryName->biriyani,
categoryCheckQuery checks the shop table whether categoryname = 'biriyani' is already exists.
3)If exists it wont be saved
Problem:
Here for both the data result.rowCount ==0 and both the data which have categoryname = biriyani is entered into shop table.
There are couple problems in this code.
One is the use of async.each(), async.eachSeries() should be used instead of async.each() because the operation of the next item in categoryList depends on current item's operation. async.eachSeries() ensures that first item is done before moving on to next item.
Another is async.each()'s callback() should be called to signal it that you're done with it.
Here is the revised code:
var categoryList = [{"categoryName": "biriyani","productName":"chicken biriyani"}, {"categoryName":"biriyani","productName":"mutton biriyani"}]
// Use async.eachSerices() instead of async.each()
async.eachSeries(categoryList, function(item,callback) {
var categoryName = item.categoryName;
var productName = item.productName;
var categoryCheckQuery = pgFormat("select * from shop where categoryName LIKE '%" + categoryName + "%'");
model.client.query(categoryCheckQuery, function (err, result) {
if (result.rowCount == 0) {
var insertCategoryQuery = pgFormat("insert into shop(categoryName)values(%L)", categoryName);
model.client.query(insertCategoryQuery, function (err, result) {
if (!err) {
console.log("success");
}
// passing non-null if you want to stop async.eachSeries() in case of error
callback(null); // <<<<< need to call async.each()'s callback() here
});
}
else {
//insert product into product table
doInsert(params, function(err, result) {
callback(null); // <<<<< need to call async.each()'s callback() here
});
}
});
});
Also, it's probably good practice to check for error returned.. specifically model.client.query() in this case

Retrieve data from MongoDB and save it to global object in Node.js and Express.js

I'm trying to get data from MongoDB collection and then save it to a global object.Later I need to parse it to HTML template.
Here is my code:
When user log onto his profile: then we need to get his projects and here we call findeprojects() function
usrRouter.route('/profile')
.all(function (req,res,next) {
if(!req.user){
res.redirect('/');
}
next();
})
.get(function (req,res,userObj) {
// var proj = findprojects();
userObj = req.user;
var pro = {};
pro = findprojects(userObj);
res.render('index',{name:userObj.username, email:userObj.email});
//res.sendFile('profile.html',{root:path.join(__dirname,'../public'),},{name:userObj.username});
});
Here is findeprojects function code:
var findprojects = function(obj) {
var usern = obj.username;
mongodb.connect(url,function(err, db){
if(err) throw err;
var collection = db.collection('projects');
//console.log(usern);
collection.find({'pusername':usern});
cursor =db.collection('projects').find({ 'pusername': usern }).toArray(function(err,items){
//console.log(items);
var i;
for(i=0; i<items.length;){
userProjects.createdBy = items[i].pusername;
userProjects.proName = items[i].projectName;
userProjects.proType = items[i].projectType;
userProjects.proDesc = items[i].projectDesc;
//return userProjects;
i = i+1;
}
});
console.log(userProjects);
});
};
I have declared global object at the top like:
userProjects = {
createdBy:'',
proName:'',
proType:'',
proDesc:''
};
But when I console userprojects object after calling the findeprojects() function it displays empty values.
why dont you use mongoose to model your stuff.
its more intuitive and you no need to declare the global object and do the mapping in the for loop that you are doing.
also your approach is a bit wrong in terms of when you iterate through for aren't you overwriting ?
say you have two documents where pusername is abdul.
so in your case you loose first object which will get overwritten by the second one.
i see that you commented out a return statement but even that wont work properly.
from a design point of view your approach is not efficient.
in mongoose you can do:
{
var userProjectSchema = new mongoose.Schema({
createdBy: { type: String }
, proName: String
, proType: String
, proDesc: String
});
// Find a single document by username.
userProjectSchema.findOne({ pusername : 'abdul' }, function(err, resDoc) {
if (err) return console.error(err);
// do your html stuff here
});
// Find all documents.
userProjectSchema.find(function(err, results) {
if (err) return console.error(err);
// do your html stuff here
});
}

Node.js Mongoose keeps adding same single element instead of all of them

In my code below, my value printed out at the console.log is correct, but when I search and go about entering the objects into the db, all the objects in the db contain the same hex, and image path but the id's are different. I tried first using findOne but the resulted in the same outcome. I am new to MongoDb so I am assuming it is just somethign I am doing stupid. Any ideas please send them my way :)
exports.addImage = function(req,res){
var params = req.body;
var colors = params.color;
var passedImg = params.path;
var ndxobj;
for(var index in colors){
ndxobj = colors[index];
//Values here are the correct index and contain valid data
console.log("col: ", ndxobj);
var query = clrModel.find({hex: ndxobj.hex}, function(err,result){
if(!err && result.length > 0){
console.log(result);
}else if(!err){
//We have an empty db for the searched obj
var locclr = new clrModel({
hex: ndxobj.hex
});
locclr.img.push({path:passedImg, date:ndxobj.imagedate});
locclr.save(function(error, data){
if(error){
console.log("Error in addImage find call: ",error);
res.json(error);
}
else{
console.log("Saving: ",data);
res.json(data);
}
});
}else {
//Handle error
}
});
}
};
I think that your paths are all the same because you set path to be passedImage, and passedImage is not updated from each index, but is set at the top of your code sample. As for the hex values being all the same, that seems to be happening because the callbacks are closing over ndxobj, so by the time they're called, all of them are looking at the same value. To make that work, you'll want to use a function to create your callbacks, something like what follows (hopefully I closed all my parens & brackets...). See this StackOverflow post for more info.
exports.addImage = function(req,res){
var makeCallback=function(ndxobj){
return function(err,result){
if(!err && result.length > 0){
console.log(result);
}else if(!err){
//We have an empty db for the searched obj
var locclr = new clrModel({
hex: ndxobj.hex
});
locclr.img.push({path:passedImg, date:ndxobj.imagedate});
locclr.save(function(error, data){
if(error){
console.log("Error in addImage find call: ",error);
res.json(error);
}else{
console.log("Saving: ",data);
res.json(data);
}
});
}else{
//Handle error
}
};
});
var params = req.body;
var colors = params.color;
var passedImg = params.path;
var ndxobj;
for(var index in colors){
ndxobj = colors[index];
//Values here are the correct index and contain valid data
console.log("col: ", ndxobj);
var query = clrModel.find({hex: ndxobj.hex}, makeCallback(ndxobj.hex));
}
};

NodeJS + Mongoose: Updating all fields on a Mongoose model

I'm building out an api using Node, MongoDB and Mongoose. One thing that is bugging me is that you can't seem to set multiple fields at once:
app.put('/record/:id', function(req, res) {
Record.findById(req.params.id, function(err, doc) {
if (!err) {
doc.update(req.params);
doc.save();
...
However, it seems that you have to work out the update query and run it on the Model object rather than on the document object. Unless you want to assign individual properties and run save() at the end.
Is there any way of accomplishing this without having to write a Mongo query?
jsaak's answer is good but doesn't work for nested objects. I elaborated on his answer by searching and setting nested objects.
I added these functions to a utility.js file
var _ = require('underscore');
exports.updateDocument = function(doc, SchemaTarget, data) {
for (var field in SchemaTarget.schema.paths) {
if ((field !== '_id') && (field !== '__v')) {
var newValue = getObjValue(field, data);
console.log('data[' + field + '] = ' + newValue);
if (newValue !== undefined) {
setObjValue(field, doc, newValue);
}
}
}
return doc;
};
function getObjValue(field, data) {
return _.reduce(field.split("."), function(obj, f) {
if(obj) return obj[f];
}, data);
}
function setObjValue(field, data, value) {
var fieldArr = field.split('.');
return _.reduce(fieldArr, function(o, f, i) {
if(i == fieldArr.length-1) {
o[f] = value;
} else {
if(!o[f]) o[f] = {};
}
return o[f];
}, data);
}
implement as:
var util = require('./utility');
app.put('/record/:id', function(req, res) {
Record.findById(req.params.id, function(err, doc) {
if (!err) {
utils.updateDocument(doc, Record, req.params);
doc.save();
...
Maybe this has changed since this question was first asked, but you can update multiple paths in Mongoose with the set method ike:
// object
doc.set({
path : value,
path2 : {
path : value
}
});
doc.save();
References
http://mongoosejs.com/docs/api.html#document_Document-set
direct updating is not recommended according to this document:
http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html
i solved it like this:
Book.findOne({isbn: req.params.isbn}, function (err, book){
if (err) {
res.send(422,'update failed');
} else {
//update fields
for (var field in Book.schema.paths) {
if ((field !== '_id') && (field !== '__v')) {
if (req.body[field] !== undefined) {
book[field] = req.body[field];
}
}
}
book.save();
}
});
If you want to update the entire document , you can delete the document based on its id and store the entire object again.
That object must contain data for each and every fields of the mongo document.
Here is an example.
mongoDBCollectionObject.findOneAndRemove({ // -- it will delete the entire document
_id: req.body.fieldsdata._id // here fiedsdata is exact copy with modification of previous data
}, function(err, data) {
var newFieldsData = new mongoDBCollectionObject(fieldsdata); //-- fieldsdata updated data
newFieldsData.save(function(err, data) { // save document to that collection with updated data
if (err) {
console.log(err);
} else
res.json({
success: true
});
});
})
To clarify the question, it looks like you are taking the Request parameters and using those to find and update the given document.
Is there any way of accomplishing this without having to write a Mongo query?
The obvious answer is to update the Model object with the value from the Request. Which is what you suggest...
Unless you want to assign individual properties and run save() at the end.
But it seems like you don't want to do this? It sounds like you want to update the Model object directly from the Request object?
You can do this if you really want. You just loop through req.params and set the doc values where appropriate.
for(var i in req.params) {
if(req.params[i] != doc[i]){
doc[i] = req.params[i];
}
}
It should be as simple as this. However, you only want to do this if you have a whole bunch of validation code on the Model objects. The whole point to the Model is that you don't want to get random data in the DB. The line above will generically "set" the correct values, but you'll definitely need to include code for authentication, authorization and validation around that simple for loop.
try to updating the collection without the find, like this
Record.update({_id:req.params.id}, {$set: { field: request.field }}, {upsert: true}, function(err{...})
The option upsert create the document if not exist.
In case you have a new object and want to update whole object in the database, you can update multiple fields at once like this:
find the object
get all schema paths (fields)
save the new object.
SomeModel.findOne({ 'id': 'yourid' },function (err, oldObject) {
if (err) return handleError(err);
// get all schema paths (fields)
SomeModel.schema.eachPath(function(path) {
// leave __id and __v alone
if (path != '_id' && path != '__v') {
// update the data from new object
oldObject[path] = newObject[path];
}
})
oldObject.save(function(err) {
if (err)
console.log(err)
});
})
A neat and clean approach would be using async await and findOneAndRemove along with create Here is the sample code
try {
let resp = await this.findOneAndRemove({ _id: req.body._id });
let entry = await this.create(req.body);
} catch (err) {
}
Don't Forget to mark this whole function as async

Resources