MongoDB aggregate with total count as variable - mongodb

I have a condition which says: Create a mongodb query that pulls 5% of total settled claims by claims examinar and my document for example is:
claims collection
{
"_id" : ObjectId("5dbbb6b693f50332a533f4db"),
"active" : true,
"status" : "settled",
}
{
"_id" : ObjectId("5dbbb6b693f50332a533f4db"),
"active" : true,
"status" : "unsettled",
}
I can calculate the total like this.
db.getCollection("claims").aggregate([
{$match: { 'status': 'trm'}},
{ $count: "total"}
])
It gives me the count of 42 for example.
So what I am trying to achieve is calculate the total count of settled data, set the total as a variable and apply the 5% of the formula in the $limit section as
{
$limit: $total * 0.05
}
I am unable to set the total from one pipeline as the variable and apply that in another pipeline.
Help please. How to achieve this type of condition?

You can do this by adding project stage and using multiply operator like this:
db.getCollection("claims").aggregate([
{
$match: {
"status": "trm"
}
},
{
$count: "total"
},
{
$project: {
"total": {
$multiply: [
"$total",
0.95
]
}
}
}
])
https://mongoplayground.net/p/VsypWLI6iJt
Docs: https://docs.mongodb.com/manual/reference/operator/aggregation/multiply

Related

Data processing before sending result back in MongoDB

We have a requirement to rank our records based on some defined algorithm. We have 4 fields in our MongoDB like following;
{
"rating" : 3.5
"review" : 4
"revenue" : 100
"used" : 3.9
},
{
"rating" : 1.5
"review" : 2
"revenue" : 10
"used" : 2.1
}
While querying the data, we will send % as weightage for our calculation. So assume we are sending 30% for rating, 30% for review and 20% each for revenue and uthe sed.
Now we need to score each record based on following calculation.
Score per column = (Existing Value - Average(Column) / StandardDeviation) * %weightage
for rating = (3.5 - 2.5) /1 * 30% = .03
So we need to count score for each column (or field) and than total of all 4 field will give a score to each record.
Is it possible to do such calculation with any MongoDB inbuilt function ?
Thanks in advance
Mongo has default operators for finding standard deviation ($stdDevPop) and for finding the average ($avg) and obviously for subtraction, multiplication, and division as well.
So, using all these operators you can definitely write an aggregation for what you require.
I've done for rating below, you can use the same logic for the other fields.
Also, replace 0.3 with your %weightage.
db.collection.aggregate([
{
$match: {
rating: {
$ne: null
}
}
},
{
$group: {
_id: null,
ratings: {
$push: "$rating"
},
avg_rating: {
$avg: "$rating"
},
std_deviation_rating: {
$stdDevPop: "$rating"
}
}
},
{
$project: {
ratings: {
$map: {
input: "$ratings",
as: "rating",
in: {
$multiply: [
{
$divide: [
{
$subtract: [
"$$rating",
"$avg_rating"
]
},
"$std_deviation_rating"
]
},
0.3
]
}
}
}
}
}
])

Get average value from array consisting of objects based on objects fields

I have a document of the following structure:
{
"_id" : ObjectId("598446bb13c7141f1"),
"trackerId" : "598446ba-fa9b-4000-8000-4ea290e",
"powerMetrics" : [
{
"duration" : 0.15,
"powerConsumption" : 0.1
},
{
"duration" : 0.1,
"powerConsumption" : 0.05
}
]
}
My goal is to get another document, which would contain a single value avgMetric. This avgMetrics should be calculated using powerMetrics array in the following way:
(powerMetrics[0].powerConsumption/powerMetrics[0].duration
+ powerMetrics[1].powerConsumption/powerMetrics[1].duration) / powerMetrics.size()
So this avgMetrics should represent the average of all (powerConsumption/duration) from the powerMetrics array.
After experimenting with query I could not achieve this,
Size of the powerMetrics array can vary, Mongo db version is 3.2.14
Could someone please help with that?
Thanks
You can use $map to with $avg to output avg in 3.2 mongo version.
db.col_name.aggregate(
[{"$project":{
"avgMetrics":{
"$avg":{
"$map":{
"input":"$powerMetrics",
"as":"val",
"in":{"$divide":["$$val.powerConsumption","$$val.duration"]}
}
}
}
}}])
db.collection.aggregate(
// Pipeline
[
// Stage 1
{
$unwind: {
path: "$powerMetrics",
preserveNullAndEmptyArrays: true // optional
}
},
// Stage 2
{
$group: {
_id: '$_id',
metrics: {
$addToSet: {
$divide: ['$powerMetrics.powerConsumption', '$powerMetrics.duration']
}
}
}
},
// Stage 3
{
$project: {
avgVal: {
$avg: '$metrics'
}
}
},
]
);

Adding Some Extra calculation during the time of Sum on mongodb $sum function

My Mongo-Db dataset is this:
{
"_id" : ObjectId("5a267533754884223467604a"),
"user_id" : "5a20ee1acdacc7086ce7742c",
"tv_count" : 1,
"ac_count" : 0,
"fridge_count" : 0,
"blower_count" : 0,
"chair_count" : 0,
"sofa_count" : 0,
"D2H_count" : 2,
"lastmodified" : ISODate("2017-12-05T10:30:30.559Z"),
"__v" : 0
}
So I know i want to do some modification during the time of Sum.
My Sum Code is this:
Accessories.aggregate([
{$match: { "lastmodified":{$gt: newTime}}},
{
$project: {
total: {
$add: [ "$tv_count", "$ac_count", "$fridge_count", "$blower_count", "$chair_count", "$sofa_count", "$D2H_count"]
}
}
}
]);
So it will return the result
[ { _id: 5a267533754884223467604a, total: 3 } ]
Now I want to do some extra calculation. Example is
Earlier Result will be 1+0+0+0+0+0+2 = 3
My desire result will be like (1*2)+0+0+0+0+0+(2*4) = 10
Any Help will be appreciated.
You can simply include additional nested calculations inside your existing projection like so:
$project: {
total: {
$add: [ { $multiply: [ "$tv_count", 2 ] }, "$ac_count", "$fridge_count", "$blower_count", "$chair_count", "$sofa_count", { $multiply: [ "$D2H_count", 4 ] }]
}
}
You should not use the $addFields or any other additional stage for this type of thing, really, since adding stages will slow down the aggregation pipeline and adding fields in particular will inflate the interim result documents between the stages so again slow down your query.
I would add an $addFields stage in the aggregation pipeline between the $match and the #project stage.
In the $addFields stage you can define new "helper fields" - eg.
{ $addFields: {
"tv_temp": { $multiply: [ "$tv_count", 2 ] },
"D2H_temp": { $multiply: [ "$D2H_count", 4 ] },
}
}
Using these fields, you can now calculate the total:
{ $project: {
total: {
$add: [ "$tv_temp", "$ac_count", "$fridge_count", "$blower_count", "$chair_count", "$sofa_count", "$D2H_temp"]
}
}}

Excluding data in mongo aggregation

I'm working with a mongodb query. Each document in the collection looks like this:
{
"_id": "12345",
"name": "Trinity Force",
"price": 3702,
"comp": [
"Zeal",
"Phage",
"Sheen",
]
}
I was working on a query that returns the 5 cheapest items (lowest price), with prices equal to 0 excluded (those trinkets though). I wrote this (sorry for poor formatting)
db.league.aggregate( { $project : { _id : 1, name: 1, price: 1, comp: 0 } },
{ $match : {price : { $gt : 0 } } },
{ $sort: { price : 1 } }).limit(5)
I ran into two problems, though; the limit function doesn't seem to work with this aggregation, and neither does the $project. The output I'm looking for should exclude the item components (hence comp: 0) and limit it to 5 outputs. Could I get some assistance, please?
db.league.aggregate(
{ $project : { _id : "$_id", name: "$name", price: "$price"} },
{ $match : { "price" : { $gt : 0 } } },
{ $sort: { "price" : 1 } },
{ $limit : 5 })
This is aggregation query to return the 5 cheapest items
imo, this is not aggregating but sorting results.
db.league.find({ price: { $gt :0} }, {comp: 0}).sort({price: 1}).limit(5)
nevertheless, i would test both for performance

MongoDB sum() data

I am new to mongoDB and nosql, what is the syntax to get a sum?
In MySQL, I would do something like this:
SELECT SUM(amount) from my_table WHERE member_id = 61;
How would I convert that to MongoDB? Here is what I have tried:
db.bigdata.aggregate({
$group: {
_id: {
memberId: 61,
total: {$sum: "$amount"}
}
}
})
Using http://docs.mongodb.org/manual/tutorial/aggregation-zip-code-data-set/ for reference you want:
db.bigdata.aggregate(
{
$match: {
memberId: 61
}
},
{
$group: {
_id: "$memberId",
total : { $sum : "$amount" }
}
})
From the MongoDB docs:
The aggregation pipeline is a framework for data aggregation modeled on the concept of data processing pipelines. Documents enter a multi-stage pipeline that transforms the documents into an aggregated results.
It would be better to match first and then group, so that you system only perform group operation on filtered records. If you perform group operation first then system will perform group on all records and then selects the records with memberId=61.
db.bigdata.aggregate(
{ $match : {memberId : 61 } },
{ $group : { _id: "$memberId" , total : { $sum : "$amount" } } }
)
db.bigdata.aggregate(
{ $match : {memberId : 61 } },
{ $group : { _id: "$memberId" , total : { $sum : "$amount" } } }
)
would work if you are summing data which is not a part of array, if you want to sum the data present in some array in a document then use
db.collectionName.aggregate(
{$unwind:"$arrayName"}, //unwinds the array element
{
$group:{_id: "$arrayName.arrayField", //id which you want to see in the result
total: { $sum: "$arrayName.value"}} //the field of array over which you want to sum
})
and will get result like this
{
"result" : [
{
"_id" : "someFieldvalue",
"total" : someValue
},
{
"_id" : "someOtherFieldvalue",
"total" : someValue
}
],
"ok" : 1
}