Multiply rows and search query - mongodb

I have to multiply rows with a number and then have to filter the data.
I have to multiply salary in field SAL by 12 for annual total and then find which one is greater than 30k.
I have already tried the multiply which is working, but after I get the data I can't filter, I tried to use match keyword also.
db.EMP.aggregate({$group:{_id:"$ENAME",Remuneration:{$sum:{$multiply:["$SAL","$COMM"]}}}})
db.EMP.aggregate([{$project:{total:{$multiply:["$SAL",12]}}} ,{$match:{"$total":{$gte:3000}}}] )
db.EMP.aggregate([{$project:{total:{$multiply:["$SAL",12]}}} ,{$gt:{"$total",30000}}] )
Data for MongoDB:

Your query using $match was very close, but you should use total instead of $total because as per the $match docs:
The $match query syntax is identical to the read operation query
syntax; i.e. $match does not accept raw aggregation expressions.
So your pipeline would be:
db.EMP.aggregate([
{ $project: { total : { $multiply : ["$SAL", 12 ] } } },
{ $match: { total : { $gt: 30000 } } }
])

Related

Cast String as Numeric in Find and Sort Operations

I have a mongo collection called items. I want to find the 10 highest priced items out of the active ones. My problem is the price is a string. So my question is how can I cast price as numeric and then sort the active items in descending order over price?
My current attempt gives me the highest price in alphanumeric order, i.e. 999. But I have items that are way pricier.
db.getCollection('items').find({"status": "active"})
.sort({"packet.price":-1})
.limit(10)
I tried:
sort({{$toInt:"packet.price"}:-1}),
sort({NumberInt("packet.price"):-1})
but no luck.
It is not possible with find method, you can use the aggregation framework,
$match to match your query condition
$addFields to change type of price field using $toInt operator
$sort by price in descending order
$limit 10 documents
db.getCollection('items').aggregate([
{ "$match": { "status": "active" }, },
{ "$addFields": { "$toInt": "$packet.price" } },
{ "$sort": { "packet.price": -1 } },
{ "$limit": 10 }
])

Does MongoDB's $in clause has any max limit in number of arguments

When using MongoDB's $in clause with Aggregate , Does That has any max limit in number of arguments ?
for example
Model.aggregate(
[
{ $match :
{ '_Id' :
{
$in : ids
}
}
} ,
{ $group :
{ _id : '$roomId' ,
maxdate: { $max: "$date"},
}
},
{$sort: { maxdate: -1} },
{$skip: skip},
{$limit: limitNum }
]
In ids array , how many ids i can pass ?
Currently i am not facing any issue with ids length till 50,000 ... but for safe side wanted to know the max limit.
I have tried to search on Mongo doc , but didnt find anything.
Thanks in advance.
There is no limit to the number of arguments in the $in clause itself, however, the total query size is limited to 16MB as a query is just a BSON document. Depending on the type used for ids (see the BSON specification), you may start running into problems when your ids length is in the order of a few millions.

Count occurrences of duplicate values

How do I structure my MongooseJS/MongoDB query to get total duplicates/occurrences of a particular field value? Aka: The total documents with custID of some value for all custIDs
I can do this manually in command line:
db.tapwiser.find({"custID" : "12345"}, {}, {}).count();
Outputs: 1
db.tapwiser.find({"custID" : "6789"}, {}, {}).count();
Outputs: 4
I found this resource:
How to sum distinct values of a field in a MongoDB collection (utilizing mongoose)
But it requires that I specify the unique fields I want to sum.
In this case, I want to loop through all documents, sum the occurrences of each.
All you need to do is $group your documents by custID and use the $sum accumulator operator to return "count" for each group.
db.tapwiser.aggregate(
[
{ "$group": { "_id": "$custID", "count": { "$sum": 1 } } }
], function(err, results) {
// Do something with the results
}
)

Get first element in array and return using Aggregate?

How can I get and return the first element in an array using a Mongo aggregation?
I tried using this code:
db.my_collection.aggregate([
{ $project: {
resp : { my_field: { $slice: 1 } }
}}
])
but I get the following error:
uncaught exception: aggregate failed: {
"errmsg" : "exception: invalid operator '$slice'",
"code" : 15999,
"ok" : 0
}
Note that 'my_field' is an array of 4 elements, and I only need to return the first element.
Since 3.2, we can use $arrayElemAt to get the first element in an array
db.my_collection.aggregate([
{ $project: {
resp : { $arrayElemAt: ['$my_field',0] }
}}
])
Currently, the $slice operator is unavailable in the the $project operation, of the aggregation pipeline.
So what you could do is,
First $unwind, the my_field array, and then group them together and take the $first element of the group.
db.my_collection.aggregate([
{$unwind:"$my_field"},
{$group:{"_id":"$_id","resp":{$first:"$my_field"}}},
{$project:{"_id":0,"resp":1}}
])
Or using the find() command, where you could make use of the $slice operator in the projection part.
db.my_collection.find({},{"my_field":{$slice:1}})
Update: based on your comments, Say you want only the second item in an array, for the record with an id, id.
var field = 2;
var id = ObjectId("...");
Then, the below aggregation command gives you the 2nd item in the my_field array of the record with the _id, id.
db.my_collection.aggregate([
{$match:{"_id":id}},
{$unwind:"$my_field"},
{$skip:field-1},
{$limit:1}
])
The above logic cannot be applied for more a record, since it would involve a $group, operator after $unwind. The $group operator produces a single record for all the records in that particular group making the $limit or $skip operators applied in the later stages to be ineffective.
A small variation on the find() query above would yield you the expected result as well.
db.my_collection.find({},{"my_field":{$slice:[field-1,1]}})
Apart from these, there is always a way to do it in the client side, though a bit costly if the number of records is very large:
var field = 2;
db.my_collection.find().map(function(doc){
return doc.my_field[field-1];
})
Choosing from the above options depends upon your data size and app design.
Starting Mongo 4.4, the aggregation operator $first can be used to access the first element of an array:
// { "my_field": ["A", "B", "C"] }
// { "my_field": ["D"] }
db.my_collection.aggregate([
{ $project: { resp: { $first: "$my_field" } } }
])
// { "resp" : "A" }
// { "resp" : "D" }
The $slice operator is scheduled to be made available in the $project operation in Mongo 3.1.4, according to this ticket: https://jira.mongodb.org/browse/SERVER-6074
This will make the problem go away.
This version is currently only a developer release and is not yet stable (as of July 2015). Expect this around October/November time.
Mongo 3.1.6 onwards,
db.my_collection.aggregate([
{
"$project": {
"newArray" : { "$slice" : [ "$oldarray" , 0, 1 ] }
}
}
])
where 0 is the start index and 1 is the number of elements to slice

MongoDB query for distinct field values that meet a conditional

I have a collection named 'sentences'. I would like a list of all the unique values of 'last_syls' where the number of entries containing that value of 'last_syls' is greater than 10.
A document in this collection looks like:
{ "_id" : ObjectId( "51dd9011cf2bee3a843f215a" ),
"last_syls" : "EY1D",
"last_word" : "maid"}
I've looked into db.sentences.distinct('last_syls'), but cannot figure out how to query based on the count for each of these distinct values.
You're going to want to use the aggregation framework:
db.sentences.aggregate([
{
$group: {
_id: "$last_syls",
count: { $sum: 1}
}
},
{
$match: {
count: { $gt: 10 }
}
}
])
This groups documents by their last_syls field with a count per group, then filters that result set to all results with a count greater than 10.