Skip to content

Instantly share code, notes, and snippets.

@ffMathy
Created August 27, 2019 13:06
Show Gist options
  • Save ffMathy/fc55c3dc1db374d26c5e3a7644eaed5a to your computer and use it in GitHub Desktop.
Save ffMathy/fc55c3dc1db374d26c5e3a7644eaed5a to your computer and use it in GitHub Desktop.
Median in MongoDB
db.Transactions.aggregate([
{
"$group": {
"_id": null,
"count": {
"$sum": 1
},
"values": {
"$push": "$INSERT_VALUE_TO_GET_MEDIAN_OF_HERE"
}
}
},
{
"$unwind": "$values"
},
{
"$sort": {
"values": 1
}
},
{
"$project": {
"values": 1,
"count": 1,
"midpoint": {
"$divide": [
"$count",
2
]
}
}
},
{
"$project": {
"values": 1,
"count": 1,
"midpoint": 1,
"high": {
"$ceil": "$midpoint"
},
"low": {
"$floor": "$midpoint"
}
}
},
{
"$group": {
"_id": null,
"values": {
"$push": "$values"
},
"high": {
"$avg": "$high"
},
"low": {
"$avg": "$low"
}
}
},
{
"$project": {
"beginValue": {
"$arrayElemAt": ["$values", "$high"]
},
"endValue": {
"$arrayElemAt": ["$values", "$low"]
}
}
}
]);
@Lemon-Lord
Copy link

Hello. This is wrong (or, at least, somewhat confusing) and does not work for collections of both odd and even lengths. I think, as is, it only works for even lengths but regardless, here is the working code that returns the median of any field in a collection.

db.test.aggregate([ { "$group":{ "_id":null, "count":{ "$sum":1 }, "values":{ "$push":"$INSERT_VALUE_TO_GET_MEDIAN_OF_HERE" } } }, { "$unwind":"$values" }, { "$sort":{ "values":1 } }, { "$project":{ "values":1, "count":1, "midpoint":{ "$divide":[ "$count", 2 ] } } }, { "$project":{ "values":1, "count":1, "midpoint":1, "high":{ "$floor":{ "$subtract":[ "$midpoint", 0.5 ] } }, "low":{ "$floor":"$midpoint" } } }, { "$group":{ "_id":null, "values":{ "$push":"$values" }, "high":{ "$avg":"$high" }, "low":{ "$avg":"$low" } } }, { "$project":{ "values":1, "beginValue":{ "$arrayElemAt":[ "$values", "$high" ] }, "endValue":{ "$arrayElemAt":[ "$values", "$low" ] } } }, { "$project":{ "median":{ "$cond":{ "if":{ "$eq":[ { "$mod":[ { "$size":"$values" }, 2 ] }, 0 ] }, "then":{ "$avg":[ "$beginValue", "$endValue" ] }, "else":"$endValue" } } } } ]);

Hope this helps :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment