mongodb find where field lower than another field plus parameter value - node.js

I have the following collection in mongodb, lets call it "products":
[
{
"name" : "Product X",
"warehouseStock" : 50,
"reservedStock" : 41
},
{
"name" : "Product Y",
"warehouseStock" : 50,
"reservedStock" : 10
}
]
I want to have a find() query that returns the documents in this collection where 'warehouseStock' is less than ('reservedStock' + threshold), where threshold is a parameter passed into the find() query.
I am trying to do the following find() query in node:
var threshold = 10;
mongo.getDb().collection('products').find({warehouseStock: {$lt:(threshold+'$reservedStock')}})
but this does not seem to work. I know I can do the following:
mongo.getDb().collection('products').find({warehouseStock: {$lt:threshold}})
but how can I query where
warehouseStock < (reservedStock + threshold)
So, if threshold was to be =10, then I would only get the first of the two items in the collection example above.
Thank you!

You can use $where :
var threshold = 10;
mongo.getDb().collection('products').find({
"$where": "this.warehouseStock < (this.reservedStock + " + threshold + ")"
}).toArray(function(err, items) {
console.log(items);
});

Related

Node JS and Firebase Unable to Search Using equal.To()

I've started reading into creating Google Actions using Node.JS/Dialogflow/Firebase.
I have reached a big stumbling block, in trying to get a simple code running that would search a Firebase database for a certain value and then report back. For example from the JSON output, I would like to search for the applicationID and have the age passed back as the output.
I would be extremely grateful if someone can review my code and direct me in the right direction.
Table Structure
{
"groupA" : {
"applications" : {
"100" : {
"age" : 20,
"result" : "pass"
},
"200" : {
"age" : 25,
" result " : "pass"
},
"500" : {
"age" : 20,
" result " : "fail"
}
}
}
}
Node JS
return admin.database().ref('groupA').child('applications').orderByChild('applications').equalTo(500)
.once('value')
.then(acceptedApplicationsSnapshot => {
var id = acceptedApplicationsSnapshot.val().age;
var data = acceptedApplicationsSnapshot.val();
var theAge = acceptedApplicationsSnapshot.child("age").val();
agent.add('some random text' + theAge);
});
Within this example the value 500 should be searched with the age then given as the output.
You're ordering/filtering on property applications, but the value you're passing in is a key. So you'll want to use orderByKey instead of orderByChild:
return admin.database().ref('groupA').child('applications').orderByKey().equalTo(500)
A query may match multiple child nodes, so the above returns a snapshot with a list of results. Even when there's only one result, the query will return a list of one result:
{
"500": {
"age" : 20,
" result " : "fail"
}
}
This means that you'll need to loop over the results in your callback:
acceptedApplicationsSnapshot.forEach(appSnapshot => {
var theAge = appSnapshot.child("age").val();
agent.add('some random text' + theAge)
})
Since you know the exact key of the child node you want, you can also simply keep using child() to access the specific node:
return admin.database().ref('groupA').child('applications').child('500')
This will result in a snapshot of that specific node being returned, instead of the list-with-a-single-child-node of the previous snippet.
{
"age" : 20,
" result " : "fail"
}
And then you can use your existing code to retrieve the age from the snapshot.
To search for the applicationsID=500 and have the age passed back as the output, you can try this.
var db = admin.database();
var ref = db.ref("groupA").child("applications/500").once('value')
.then(function(dataSnapshot){
console.log(dataSnapshot.val().age);
});
More info here.
Edited: This should give you the age, in this case equals 20, for the parameter you pass in applications/500 in the code above.
Let me know if it helps.

Why $limit in mongoose with aggregation not return all results?

I've following aggregation query, which has $limit I've set it's working fine if I pass a number between 1 to any positive integer. Now, I need all results than I pass limit: 0 So, it's through me ERROR.
Assert: command failed: {
"ok" : 0,
"errmsg" : "the limit must be positive",
"code" : 15958,
"codeName" : "Location15958"
} : aggregate failed
Query
var limit = 0; // working with 1 to infinite ( any positive integrer )
db.getCollection('abc').aggregate([
{
$match : {}
},
{
$limit: limit
}
])
Let me come out of this If anyone knows how should I return all documents from a database with $limit.
Build up your pipeline to only include the $limit element when it's needed:
var pipeline = [{$match: {}}];
if (limit) {
pipeline.push({$limit: limit});
}
db.getCollection('abc').aggregate(pipeline);

Passing variables into a query in mongoose in the first argument

I am using MEAN stack, i have an entry like this in my mongodb
{ "_id" : ObjectId("5577467683f4716018db19ed"),
"requestMatrix" : { "1698005072" : { "rideId" : "641719948", "status" :"accepted" },"1698005073" : { "rideId" : "641719545", "status" :"rejected" } },
"partners":[ { "customerNumber" : 1698005072 }, { "customerNumber" : 1698072688 } ]}
I want to query the db to return me this entire document based on whether the status is accepted or rejected.
When I run the below query in a command prompt, i get the expected answer
db.joinedrides.find({'requestMatrix.1698005072.status':"accepted"})
But when i want to do the same from nodeJs, I am stuck as the number 1698005072 in the above query is a variable, i am not able to write a query for that.
tried something like this
var criteria = "'requestMatrix.'"+customerNumber+"'.status'";
JoinedRide.find({criteria:"accepted"},function(err,joinedRides){
})
where customerNumber will vary for different requests, in the above mentioned case its value is 1698005072
Any help is appreciated.
You need to do something like this:
var query = {};
var criteria = "requestMatrix." + customerNumber + ".status";
query[criteria] = "accepted"
JoinedRide.find(query,function(err,joinedRides){
})

MongoDB Location NearBy unique

I have created a collection in DB and updated with proper indexing to retrieve it back. Im getting with the folloging
Example:
db.car.save({ "name":"Toyota car", "affiliation":"Toyota", "loc":{"lon":55.93939251390387,"lat":-113.999}})
db.car.find({"loc" : {"$within" : {"$center" : [[50.93939251390,-114],5]}}})
I have 100K + records in Database when I search the above query returns 20K records.
Actually this has some duplicate values in the "name" column. How can I get the distinct value of "name".
You can't get the results you need using a query in MongoDB 2.0.x, so will need to manipulate the results in your application code.
If you are only after names you can limit the fields in the output:
db.car.find(
{"loc" : {"$within" : {"$center" : [[50.93939251390,-114],5]}}},
{"_id": 0, "name": 1}
)
If you want to find distinct names you could do something like:
// Save cars we've seen
> var cars_seen = {}
// The unique list we actually want
> var cars = []
// Find closest cars to given geo point
> db.car.find(
{"loc" : {"$within" : {"$center" : [[50.93939251390,-114],5]}}},
{"_id": 0, "name": 1}
).forEach(
function(doc) {
// Add names we haven't seen yet
if (!cars_seen[doc.name]) {
cars_seen[doc.name] = 1;
cars.push(doc.name);
}
}
)
> cars
[ "Skoda", "Benz", "Skoda SUV" ]

Mongo custom multikey sorting

Mongo docs state:
The Mongo multikey feature can automatically index arrays of values.
That's nice. But how about sorting based on multikeys? More specifically, how to sort a collection according to array match percentage?
For example, I have a pattern [ 'fruit', 'citrus' ] and a collection, that looks like this:
{
title: 'Apples',
tags: [ 'fruit' ]
},
{
title: 'Oranges',
tags: [ 'fruit', 'citrus' ]
},
{
title: 'Potato',
tags: [ 'vegetable' ]
}
Now, I want to sort the collection according to match percentage of each entry to the tags pattern. Oranges must come first, apples second and potatoes last.
What's the most efficient and easy way to do it?
As of MongoDB 2.1 a similar computation can be done using the aggregation framework. The syntax is something like
db.fruits.aggregate(
{$match : {tags : {$in : ["fruit", "citrus"]}}},
{$unwind : "$tags"},
{$group : {_id : "$title", numTagMatches : {$sum : 1}}},
{$sort : {numTagMatches : -1}} )
which returns
{
"_id" : "Oranges",
"numTagMatches" : 2
},
{
"_id" : "Apples",
"numTagMatches" : 1
}
This should be much faster than the map-reduce method for two reasons. First because the implementation is native C++ rather than javascript. Second, because "$match" will filter out the items which don't match at all (if this is not what you want, you can leave out the "$match" part, and change the "$sum" part to be either 1 or 0 depending on if the tag is equal to "fruit" or "citrus" or neither).
The only caveat here is that mongo 2.1 isn't recommended for production yet. If you're running in production you'll need to wait for 2.2. But if you're just experimenting on your own you can play around with 2.1, as the aggregation framework should be more performant.
Note: The following explanation is required for Mongo 2.0 and earlier. For later versions you should consider the new aggregation framework.
We do something similar while trying to fuzzy-match input sentence which we index. You can use map reduce to emit the object ID every time you get a match and them sum them up. You'll then need to load the results into your client and sort by the highest value first.
db.plants.mapReduce(
function () {
var matches = 0;
for (var i = 0; i < targetTerms.length; i++) {
var term = targetTerms[i];
for (var j = 0; j < this.tags.length; j++) {
matches += Number(term === this.tags[j]);
}
}
emit(this._id, matches);
},
function (prev, curr) {
var result = 0;
for (var i = 0; i < curr.length; i++) {
result += curr[i];
}
return result;
},
{
out: { inline: 1 },
scope: {
targetTerms: [ 'fruit', 'oranges' ],
}
}
);
You would have you pass your ['fruit', 'citrus' ] input values using the scope parameter in the map reduce call as {targetTerms: ['fruit', 'citrus' ]} so that they are available in the map function above.

Resources