Mongodb GeoSpatial Query with NodeJs (Haversine formula) - node.js

I have a collection where I am storing 2 locations for every entry. These locations are
the starting point and destination point for a particular route. I know I can write the following query to find the nearby places to query for a particular location:
exports.nearby = function(req, res){
db.testpool.find({
fromLoc: {
$near: [28.423168, 77.045639],
$maxDistance: 1
},
}).toArray(function(err, doc){
res.send(doc);
if(err)
console.log(err+'');
else
{
res.send(doc+'');
}});
But i dont know the query which i should make in order to find the relevant routes which
not only match fromLoc but also the toLoc and i keep getting error When i do something like this :-
exports.nearby = function(req, res){
db.testpool.find({
fromLoc: {
$near: [28.423168, 77.045639],
$maxDistance: 1
},
toLoc: {
$near: [28.649573, 77.125284],
$maxDistance: 1
}
}).toArray(function(err, doc){
res.send(doc);
if(err)
console.log(err+'');
else
{
res.send(doc+'');
}
});
So basically I want to find out the most relevant car pools entered by users which will have
2 locations per entry, e.g. starting location and destination location.

Rigth now you can't have more than one geospatial index per collection*. If you want two indexes you will need at least two differents collections. MongoDB does not have joins but you can create fields that points to another document elsewhere. Those are called DBRefs and are least powerful than proper joins but can be used for similar purposes. There are strategies supported by those "pseudo-joins" in drivers of node.js like the mongoose's populate.
You will not be able to do what you want with a simple query at least until mongoDB supports multiples geospatial indexes. You will need to code it.
For example, we can have two collections. One with the routes and the other ones with locations. The one with the locations is similar to this:
{
"geo": [1,2],
"origin": [/*dbrefs array*/],
"destination": [/*dbrefs array*/]
}
Then we make two queries, one searching places near to the origin, the other one with places near the destinations. When we already have the result of both queries we do the intersection of the origin field of the first query with the destination field of the second one. To compare two objects you can use deepEqual in the assert library:
var intersection = originField.filter(function(origin){
for(var k in destinationField){
if(deepEqual(destinationField[k],origin)){
return true;
};
};
return false;
})
We have the DBRefs of the desired routes that contains it's collection ant _id so now we only needs to query those routes. Do it in a row with $in.
Hope this helps.
*Check issue 2331 in mongodb's jira.

Related

How to exclude specific fields from the query condition?

I am creating a webapp for users to query data from mongodb. I have front end using react and backend with nodejs hooking up mongodb.
I have included all relevant matching conditions under aggregate function. However I would like to have the effect of commenting out certain key-value pair, (by this I mean nullifying the effect of the query field condition). For example,
router.get('/getmongo', function(req, res) {
MongoClient.connect(process.env.DB_CONN, function(err, db) {
if (err) throw err;
db.aggregate([
{
$match:{
'employmentStatus':/employed|unemployed/i,
'gender':{$in:["male","female"]},
'age':{$gte:20, $lte:30}
}
},
{ "$group": {
"_id": "$employmentStatus",
"count": { "$sum": 1 }
}}
]).limit(4).toArray(function(err, docs) {
if (err) throw err;
res.send(JSON.stringify(docs))
db.close();
})
})
Let say on front end, the user does not select the option of age, which means there is no specification from the user's end on the age criteria. Usually for this case, users would comment out or remove the whole line of age query on MongoDB GUI, leaving only employmentStatus and gender as the only two criteria to query. I was looking into mongoAPI but can't find any useful tool to replicate that effect. Any idea or suggestion?
(I am using Mongo v2.3.3 by the way)
Instead of adding conditions in the Query at MongoDB side, you should build your query conditionally based on user input.
Whenever user selects the columns, build the $match clause using those columns and values. In that way, it will be quite dynamic.
Example PseudoCode:
var queryObject = {};
if(age.selected)
queryObject.add(ageCondition)
if(employmentStatus.selected)
queryObject.add(employmentStatusCondition)
if(gender.selected)
queryObject.add(genderCondition)
.....
......
You can build some logic like this in Node.js.

Mongoose & MongoDB: Retrieve results narrowed by multiple parameters

I need to get data from MongoDB that is first narrowed by one initial category, say '{clothing : pants}' and then a subsequent search for pants of a specific size, using an array like sizes = ['s','lg','6', '12'].
I need to return all of the results where 'pants' matches those 'sizes'.
I've started a search with:
Product.find({$and:[{categories:req.body.category, size:{$in:req.body.sizes}}]},
function(err, products) {
if (err) { console.log(err); }
return res.send(products)
});
I really don't know where to go from there. I've been all over the Mongoose docs.
Some direction would be very helpful.
The mongoose queries can receive object like Mongodb would. So you can pass the search parameters separated by ,
Product.find({categories:req.body.category, size:{$in:['s','lg','6', '12']}})
For more information on $in, check here
For more information on $and operator, check here (note we can ommit the $and operator in some cases and that is what I did)

MongoDB: How to find a document sharing a list element with specified list

I'm currently using mongoose schemas where some of the values hold lists. For example:
var dinerSchema = mongoose.Schema({
restaurants: [String]
});
I'm looking for a way to write a mongo query that finds other documents which have at least one shared element between the two values. For example if I'm given a list of restaurants which is
[McDonalds, Burger King, Wendy's]
I want to find other documents which have restaurant values such as
[Sonic, Taco Bell, Burger King]
but not
[Red Lobster, Olive Garden, Legal Sea Foods]
I'm aware if I wanted to find documents given a single value I could do something like
dinerModel.find({ restaurants: "McDonalds" }, ...);
To return all documents which contain McDonalds in their restaurant list. However, I want to find any documents which contain ANY of the elements in a certain list. Is there a way to query for this? I don't think I can just do "or" queries because I don't know the size of the list of restaurants that I'll be looking for, and it could change from query to query.
Thanks!
Do a find with $in clause :
dinerModel.find({
'restaurants': { $in: [
'Sonic',
'Taco Bell',
'Burger King'
]}
}, function(err, docs){
if (err) {
console.log(err); // deal somehow
return;
}
console.log(docs);
}
});

Loopback query which compares field values

Say i have the following Scheme
Product: {
Quantity: Number,
SelledQuantity: Number
}
Would it be possible to write a query where all the results returned are where Quantity=SelledQuantity?
If so, is there a way to use it when doing a populate? (Perhaps inside the match field in the opts object ?)
I use mysql connector.
yes as I understood your problem you can do this by following rest call.
http://localhost:3000/api/products?filter[where][SelledQuantity]=n
this will give you the desired results.
This question is more related to MySQL query. But you can achieve it by javascript as follows:
Product.find({}, fuction(err, products) {
if(err) throw err;
//considering products as array of product. Otherwise you can get to depth for array of product.
var filteredProducts = products.filter(function(p1) {
return p1.Quantity === p1.SelledQuantity;
});
//Your desired output
console.log(filteredProducts);
});
This will be slow but will work for smaller database size. For more optimized answer, ask the question in mysql section with respect to database and table structure.

Using the find method on a MongoDB collection with Monk

I am working through a MEAN stack tutorial. It contains the following code as a route in index.js. The name of my Mongo collection is brandcollection.
/* GET Brand Complaints page. */
router.get('/brands', function(req, res) {
var db = req.db;
var collection = db.get('brandcollection');
collection.find({},{},function(e,docs){
res.render('brands', {
"brands" : docs
});
});
});
I would like to modify this code but I don't fully understand how the .find method is being invoked. Specifically, I have the following questions:
What objects are being passed to function(e, docs) as its arguments?
Is function(e, docs) part of the MongoDB syntax? I have looked at the docs on Mongo CRUD operations and couldn't find a reference to it. And it seems like the standard syntax for a Mongo .find operation is collection.find({},{}).someCursorLimit(). I have not seen a reference to a third parameter in the .find operation, so why is one allowed here?
If function(e, docs) is not a MongoDB operation, is it part of the Monk API?
It is clear from the tutorial that this block of code returns all of the documents in the collection and places them in an object as an attribute called "brands." However, what role specifically does function(e, docs) play in that process?
Any clarification would be much appreciated!
The first parameter is the query.
The second parameter(which is optional) is the projection i.e if you want to restrict the contents of the matched documents
collection.find( { qty: { $gt: 25 } }, { item: 1, qty: 1 },function(e,docs){})
would mean to get only the item and qty fields in the matched documents
The third parameter is the callback function which is called after the query is complete. function(e, docs) is the mongodb driver for node.js syntax. The 1st parameter e is the error. docs is the array of matched documents. If an error occurs it is given in e. If the query is successful the matched documents are given in the 2nd parameter docs(the name can be anything you want).
The cursor has various methods which can be used to manipulate the matched documents before mongoDB returns them.
collection.find( { qty: { $gt: 25 } }, { item: 1, qty: 1 })
is a cursor you can do various operations on it.
collection.find( { qty: { $gt: 25 } }, { item: 1, qty: 1 }).skip(10).limit(5).toArray(function(e,docs){
...
})
meaning you will skip the first 10 matched documents and then return a maximum of 5 documents.
All this stuff is given in the docs. I think it's better to use mongoose instead of the native driver because of the features and the popularity.

Resources