Mongodb multiple conditions - node.js

New to MongoDB and express interactions. I'm trying to query the database based on URL parameters, essentially I want to grab URL parameters then add them to an object if they exist to use when querying the database. I set up my express path and understand that the find() method accepts an object, when I hard code the key-value pair like below I get the correct data but when I set an object called filter with the same key-value pairs as the hard-coded example and uncomment filter and comment state and type then pass it to the find method I get an empty array. Whats the reason for this and what's the best way to achieve this?
app.get('/query', function (req, res) {
var filter = {
state: "florida",
type: "red"
}
db.collection('tickets').find({
//filter
state:"florida",
type:"red"
})
.toArray(function (err, documents) {
// Here is where we decide what to do with the query results
if (err)
throw err
res.send(documents)
})
});

The find method accepts a query object as the first parameter, the query object is your filter object yourself. therefore, you should do it like this:
db.collection('tickets').find(filter)
.toArray(function (err, documents) {
// Here is where we decide what to do with the query results
if (err)
throw err
res.send(documents)
})

Related

Skip fields on collection.find() not working

I'm developing a report system in Node.JS and MongoDB
I'm trying to make a query to get some datas from the MongoDB, but the query don't specify all the fields that the collection have
(example, in the query I'm asking for the field typ, event and date, but in the collection I have more than 10 fields).
db.collection('logs').find({
system: {
type: query.logType,
event: query.event,
date: query.date
}
}).toArray(function (err, document) {
if (err) throw err;
console.log(document);
});
This way, it doesn't return anything, but when I specify all the fields that the collection have, the query works.
Is there any way to use RegEx or skip the other not-needed fields on the query?
you can use map and select properties in that function
let tmp = [{id:1,name:"aaa"},{id:2,name:"bbb"}].map((item)=>{
// your can make new object here
return {name: item.name};
});
console.log(tmp);

Limit posted fields for insert

I'm trying to limit the fields a user can post when inserting an object in mongodb. I know ho i can enforce fields to be filled but I can't seem to find how to people from inserting fields that I don't want.
This is the code I have now for inserting an item.
app.post("/obj", function (req, res) {
var newObj = req.body;
//TODO filter fields I don't want ?
if (!(newObj .id || newObj .type)) {
handleError(res, "Invalid input", "Must provide a id and type.", 400);
return;
}
db.collection(OBJ_COLLECTION).insertOne(newObj, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to create new object.");
} else {
res.status(201).json(doc.ops[0]);
}
});
});
There's likely JS native ways to do this, but I tend to use Lodash as my toolbox for most projects, and in that case what I normally do is setup a whitelist of allowed fields, and then extract only those from the posted values like so:
const _ = require('lodash');
app.post("/obj", function (req, res) {
var newObj = _.pick(req.body, ['id', 'type','allowedField1','allowedField2']);
This is pretty straightforward, and I usually also define the whitelist somewhere else for reuse (e.g. on the model or the like).
As a side note, I avoid using 'id' as a field that someone can post to for new objects, unless I really need to, to avoid confusion with the autogenerated _id field.
Also, you should really look into mongoose rather than using the straight mongodb driver, if you want to have more model-based control of your documents. Among other things, it will strip any fields off the object if they're not defined in the schema. I still use the _.pick() method when there are things that are defined in the schema, but I don't want people to change in a particular controller method.

Why can't I seem to merge a normal Object into a Mongo Document?

I have a data feed from a 3rd party server that I am pulling in and converting to JSON. The data feed will never have my mongoDB's auto-generated _ids in it, but there is a unique identifier called vehicle_id.
The function below is what is handling taking the data-feed generated json object fresh_event_obj and copying its values into a mongo document if there is a mongo document with the same vehicle_id.
function update_vehicle(fresh_event_obj) {
console.log("Updating Vehicle " + fresh_event_obj.vehicleID + "...");
Vehicle.find({ vehicleID: fresh_event_obj.vehicleID }, function (err, event_obj) {
if (err) {
handle_error(err);
} else {
var updated = _.merge(event_obj[0], fresh_event_obj);
updated.save(function (err) {
if (err) {
handle_error(err)
} else {
console.log("Vehicle Updated");
}
});
}
});
}
The structures of event_obj[0] and fresh_event_obj are identical, except that event_obj[0] has _id and __v while the "normal" object doesn't.
When I run _.merge on these two, or even my own recursive function that just copies values from the latter to the former, nothing in the updated object is different from the event_obj[0], despite fresh_event_obj having all new values.
Does anyone have any idea what I'm doing wrong? I feel it is obvious and I'm just failing to see it.
The problem is that if you don't have properties defined in your schema, and if they don't already exist, you can't create them with
doc.prop = value
even if you have {strict:false} in your schema.
The only way to set new properties is to do
doc.set('prop', value)
(You still have to have {strict:false} in your schema if that property doesn't exist in your schema)
As for having too many properties to be defined in schema, you can always use for-in loop to go through object properties
for(key in fresh_event_obj)
event_obj.set(key, fresh_event_obj[key]);

Why is Model.save() not working in Sails.js?

Save() giving me error like "Object has no method 'save'"
Country.update({id:req.param('country_id')},model).exec(function(err,cntry){
if(err) return res.json(err);
if(!cntry.image){
cntry.image = 'images/countries/'+filename;
cntry.save(function(err){ console.log(err)});
}
})
Any Idea about how to save model within update query . ??
Assuming you're using Waterline and sails-mongo, the issue here is that update returns an array (because you can update multiple records at once), and you're treating it like a single record. Try:
Country.update({id:req.param('country_id')},model).exec(function(err,cntry){
if(err) return res.json(err);
if(cntry.length === 0) {return res.notFound();}
if(!cntry[0].image){
cntry[0].image = 'images/countries/'+filename;
cntry[0].save(function(err){ console.log(err)});
}
});
This seems to me an odd bit of code, though; why not just check for the presence of image in model before doing Country.update and alter model (or a copy thereof) accordingly? That would save you an extra database call.
When using mongoose (3.8) to update the database directly the callback function receives 3 parameters, none of then is a mongoose object of the defined model. The parameters are:
err is the error if any occurred
numberAffected is the count of updated documents Mongo reported
rawResponse is the full response from Mongo
The right way is, first you fetch and then change the data:
Country.findOne({id: req.param('country_id')}, function (err, country) {
// do changes
})
Or using the update method, the way you intended:
Country.update({id: req.param('country_id'), image: {$exists: false}}, {image: newValue}, callback)

How to get array of json objects rather than mongoose documents

When I do the .find operation like the following:
Collection.find({name: 'Erik'}, function (err, docs) {
// do momething
});
'docs' variable is populated with an array of fully functional mongoose documents. But I need to get an array of pure JSON objects.
I know I can loop through the 'docs' array by forEach and get an objects by using .toJSON() method. Does mongoose support the feature, I'm interested?
If you're using Mongoose 3.x you can use the lean query option to do this:
Collection.find({name: 'Erik'}).lean().exec(function (err, docs) {
// docs are plain javascript objects instead of model instances
});
.exec(function(err, docs){
docs= docs.map(o => o.toObject());
This will include virtuals and getters
Map through results and convert each to JS object:
const result = await model.find({some: 'query'});
return result.map((r) => r.toObject());

Resources