MongoDB Select Values above Average - mongodb

I am trying to find the products whose price is above the average price.
I know how to get the average:
db.products.aggregate([{
"$group": {
"_id": null,
"average": { "$avg": "$price" }
}
},
{ $project : { _id : 0 } } ])
But how can I use it in a $gt clause?
For instance, I tried to save the result in a variable:
var averageValue =
db.products.aggregate([{
"$group": {
"_id": null,
"average": { "$avg": "$price" }
}
},
{ $project : { _id : 0 } } ])
And then use it in the $gt clause:
db.products.find({ "price": { "$gt": averageValue} })
However, it does not seem to print me anything.
I am also wondering if this is possible to be done in a single query.

If you use MongoDB version 5.0, you can use $setWindowFields to perform the average for all documents in the collection and add the field with result to each document.
Performs operations on a specified span of documents in a collection, known as a window, and returns the results based on the chosen window operator.
db.products.aggregate([
{
"$setWindowFields": {
"output": {
"average": {
"$avg": "$price"
}
}
}
},
{
$match: {
$expr: {
$gt: [
"$price",
"$average"
]
}
}
}
])
Sample Mongo Playground

Related

query that returns both aggregated data as well as filtered documents

{
A: "number"
}
How to write a MongoDB aggregation pipeline that returns both:
the list of documents where A > 100
and the average of all the documents returned?
In other words, this query must return both the granular filtered documents and then a grouped statistic, which is the average.
You can do it with $facet stage in the Aggregation pipeline:
db.collection.aggregate([
{
"$match": {
"A": {
"$gt": 100
}
}
},
{
"$facet": {
"list": [],
"average": [
{
"$group": {
"_id": null,
"value": {
"$avg": "$A"
}
}
}
]
}
}
])
Working example

Fetching sum of rows for a type of column value in mongodb as a single output

I am trying to get the sum of field 'score.number' based on the type of a column value work.type in MongoDB. It should fetch sum as 25 for 'hw' ,and 'cw' as 5 as a single output for the student 'A'. Is there a way to achieve it using mongodb queries ? I tried the $group as well but it doesn't seem to fetch the worktype and the sum for each worktype against it for a single student record 'A'.
Expected Output:
after $match you should use $group like this
db.collection.aggregate([
{
$match: {
student: {
$in: [
"A"
]
},
"work.type": {
$in: [
"hw",
"cw"
]
}
}
},
{
"$group": {
"_id": {
"worktype": "$work.type",
"student": "$student"
},
"workScore": {
"$sum": "$score.number"
}
}
}
])
https://mongoplayground.net/p/qzghM5KoAbp
Able to get the sum with these two
$match{
'student': {'$in': ['A']},
"work.type": {'$in': ['hw', 'cw']},
}
followed by
$group
{
_id: '$work.type',
totalAmount: { $sum: "$score.number" },
}
$match {'student': {
$in: [
"A"
]
},
"work.type": {
$in: [
"hw",
"cw"
]
}}
followed by
$group {
"_id": {
"worktype": "$work.type",
"student": "$student"
},
"workScore": {
"$sum": "$score.number"
}
}
followed by
$group {"_id": {
"student": "$_id.student"
},
'list': {'$push': {'worktype':"$_id.worktype", 'workScore': "$workScore" }},
}
Solved output:
Solves the issue.

How get and use list of fields' name in MongoDB?

I store price changes data for each date in MongoDB as following:
{ "_id" : "A1",
"Price" :
{
"2020-08-25": {"P" : [1200, 1300, 1250]},
"2020-08-26": {"P" : [1310, 1400, 1200]},
"2020-08-27": {"P" : [1500, 1300, 1300]},
...
}
},
{ "_id" : "A2",
"Price" :
{
"2020-08-25": {"P" : [1200, 1300, 1250]},
"2020-08-26": {"P" : [1310, 1400, 1200]},
"2020-08-27": {"P" : [1500, 1300, 1300]},
...
}
}
Now, I want to get maximum price for all dates. How I can do it without writing each date field in my query? I mean, for a specific date like as "2020-08-25", someone can uses $group and $max to obtain maximum price value in that date. But, how write a query to get maximum price value among all dates?
Thanks
To get the maximum price for all dates in the collection you need to run an aggregate operation that first gets the maximum for each document and this can be achieved using the $max and $map operators to create an array of price values which can be easily extrapolated for a maximum value.
To get the array values you first need to convert the Price document to an array of key/value pairs of dates and the prices using $objectToArray
db.getCollection('collection').aggregate([
{ '$set': {
'maxPricePerDocument': {
'$max': {
'$map': {
'input': { '$objectToArray': '$Price' },
'in': { '$max': '$$this.v.P' }
}
}
}
} },
{ '$group': {
'_id': 0,
'maxPriceForEntireCollection': { '$max': '$maxPricePerDocument' }
} }
])
Update:
To get across the collection
db.collection.aggregate([
{
$project: {
"prices": {
"$objectToArray": "$Price"
}
}
},
{
$group: {
"_id": null,
P: {
$addToSet: {
$max: "$prices.v.P"
}
}
}
},
{
$project: {
"maxPrice": {
$max: {
$first: "$P"
}
}
}
}
])
play
Date specific:
playground
db.collection.aggregate([
{
$project: {
"prices": {//reshape it to perform object wise operations - mainly converting to array
"$objectToArray": "$Price"
}
}
},
{//getting one by one entries
"$unwind": "$prices"
},
{
$group: {//grouping by date and getting the max from local entry
"_id": "$prices.k",
"values": {
$max: "$prices.v.P"
}
}
},
{
$project: {
"date": "$_id",
"maxPrice": {//getting the max across multiple entries
$max: "$values"
},
"_id": 0
}
}
])

How to find max and min value from embedded documents in Mongodb

So i have this json file:
{"_id":190,"name":"Adrien Renda","scores":[{"score":64.16109192679477,"type":"exam"},{"score":66.93730600935531,"type":"quiz"},{"score":96.0560340227047,"type":"homework"}]}
{"_id":191,"name":"Efrain Claw","scores":[{"score":94.67153825229884,"type":"exam"},{"score":82.30087932110595,"type":"quiz"},{"score":75.86075840047938,"type":"homework"}]}
{"_id":192,"name":"Len Treiber","scores":[{"score":39.19832917406515,"type":"exam"},{"score":98.71679252899352,"type":"quiz"},{"score":44.8228929481132,"type":"homework"}]}
{"_id":193,"name":"Mariela Sherer","scores":[{"score":47.67196715489599,"type":"exam"},{"score":41.55743490493954,"type":"quiz"},{"score":70.4612811769744,"type":"homework"}]}
{"_id":194,"name":"Echo Pippins","scores":[{"score":18.09013691507853,"type":"exam"},{"score":35.00306967250408,"type":"quiz"},{"score":80.17965154316731,"type":"homework"}]}
{"_id":195,"name":"Linnie Weigel","scores":[{"score":52.44578368517977,"type":"exam"},{"score":90.7775054046383,"type":"quiz"},{"score":11.75008382913026,"type":"homework"}]}
{"_id":196,"name":"Santiago Dollins","scores":[{"score":52.04052571137036,"type":"exam"},{"score":33.63300076481705,"type":"quiz"},{"score":78.79257377604428,"type":"homework"}]}
{"_id":197,"name":"Tonisha Games","scores":[{"score":38.51269589995049,"type":"exam"},{"score":31.16287577231703,"type":"quiz"},{"score":79.15856355963004,"type":"homework"}]}
{"_id":198,"name":"Timothy Harrod","scores":[{"score":11.9075674046519,"type":"exam"},{"score":20.51879961777022,"type":"quiz"},{"score":64.85650354990375,"type":"homework"}]}
{"_id":199,"name":"Rae Kohout","scores":[{"score":82.11742562118049,"type":"exam"},{"score":49.61295450928224,"type":"quiz"},{"score":28.86823689842918,"type":"homework"}]}
in a mongodb collection. And i'm trying to read the maximum and minimum score of the last 5 students and display them. I'm using mongolite in r studio and i've tried this:
res2 = con$aggregate(
'[{"$group":{"_id": "$_id", "MaxScore": {"$max": "$scores.score"}, "MinScore":{"$min":"$scores.score"}}},
{ "$sort" : { "_id" : -1} },
{"$limit": 5}
]'
)
The sorting and limit work just fine but the scores come out wrong. I'm guessing because they're embedded documents but i have no idea how to fix it.
This is the end result of the above command
You don't need to perform $group query to calculate $max / $min scores, you can calculate them during $project stage
db.collection.aggregate([
{
"$project": {
"_id": 1,
"MaxScore": {
"$max": "$scores.score"
},
"MinScore": {
"$min": "$scores.score"
}
}
},
{
"$sort": {
"_id": -1
}
},
{
"$limit": 5
}
])
MongoPlayground
If you want $group code working, just add before $group stage $unwind operator like below:
db.collection.aggregate([
{
$unwind: "$scores"
},
{
$group: {
_id: "$_id",
MaxScore: {
$max: "$scores.score"
},
MinScore: {
$min: "$scores.score"
}
}
},
{
"$sort": {
"_id": -1
}
},
{
"$limit": 5
}
])
MongoPlayground

How to get top level elements as well as one level down array elements aggregate in one mongo query?

I have 2 mongo aggregate queries that work well separately -
db.transfer_orders.aggregate([
{
$match: {
"request_timestamp": { $gte: ISODate("2017-10-00T00:00:00.000Z") },
"request_timestamp": { $lt: ISODate("2017-10-12T00:00:00.000Z") },
"purpose": "POSITIONING"
}
},
{
$group: {
_id: null,
to_count: { $sum: 1 },
qty: { $sum: "$quantity" }
}
},
{
$project: {
_id: 0,
"to_count": "$to_count",
"qty": "$qty"
}
}
])
and
db.transfer_orders.aggregate([
{
$match: {
"request_timestamp": { $gte: ISODate("2017-10-00T00:00:00.000Z") },
"request_timestamp": { $lt: ISODate("2017-10-12T00:00:00.000Z") },
"purpose": "POSITIONING"
}
},
{
$unwind: "$adjustments"
},
{
$group: {
_id: null,
totalChangeQty: { $sum: "$adjustments.change_in_quantity"}
}
},
{
$project: {
_id: 0,
"adjusted_quantity": "$totalChangeQty"
}
}
])
The first query returns aggregate data of elements at the top level of the document, { "to_count" : 7810, "qty" : 19470 }
The second query returns aggregate data of elements at one level below the top level for the "adjustments" array - { "adjusted_quantity" : -960 }
Is there a way to write this as one query that will return both sets of data since the match criteria is the same for both?
The following aggregate operation should suffice since it has a pipeline after the $match step that introduces the new field adjusted_quantity. This is made possible using the $sum which returns the sum of the specified list of expressions for each document.
Once it reaches the $group stage, you can retain the value using the $sum operator.
db.transfer_orders.aggregate([
{
"$match": {
"request_timestamp": { "$gte": ISODate("2017-10-00T00:00:00.000Z") },
"request_timestamp": { "$lt": ISODate("2017-10-12T00:00:00.000Z") },
"purpose": "POSITIONING"
}
},
{
"$addFields": {
"adjusted_quantity": {
"$sum": "$adjustments.change_in_quantity"
}
}
},
{
"$group": {
"_id": null,
"to_count": { "$sum": 1 },
"qty": { "$sum": "$quantity" },
"adjusted_quantity": { "$sum": "$adjusted_quantity" }
}
}
])