MongoDB: How can I calculate total count without using $group operator - mongodb

I have following result:
"result" : [
{
"_id" : "London",
"count" : 499
},
{
"_id" : "Paris",
"count" : 135
},
{
"_id" : "Lviv",
"count" : 95
}
]
And here is query:
{"$group":{
_id: "$city",
"count" : {"$sum":1}
}
}
So, I want some how to calculate all fields not only grouped. I think it would better to show expected result:
"result" : [
{
"_id" : "London",
"count" : 499,
"total" : 729
},
{
"_id" : "Paris",
"count" : 135,
"total" : 729
},
{
"_id" : "Lviv",
"count" : 95,
"total" : 729
}
]
Expected result has "total" field which calculated as amount of "count" field (499+135+95 = 729).
EDITED: I must use only aggregation framework!
Can someone help me with this?

You have to count the total number before:
db.coll.count( ..., function( err, total ) {
and then use that result in your aggregation command:
{
"$group": {
_id: "$city",
count: { "$sum": 1 },
total: total
}
EDIT:
If you only want to use aggregation framework, try this instead of db.coll.count():
{
"$group": {
_id: 1,
count: { "$sum": 1 }
}
}

Sounds like db.collection.count() would give you your result actually. This is because you are actually just summing up ALL documents in the collection there.

Related

How to limit number of returned objects in group query

I have a Mongodb database with several hundred records, each with a value for the field "pauseTime." I would like to count the number of records for each value of pauseTime. But I want to limit the query to the documents where pauseTime greater than 50 and less than 150.
I got so far as counting the number of each each value for pauseTime.
This is a record of the database:
{
"_id" : ObjectId("5ca74a95a094b08e97bd1278"),
"duration" : NumberInt(857),
"videoUrl" : "https://vimeo.com/3766858",
"pauseTime" : NumberInt(493),
"contentType" : "Comment",
"comment" : "vsvdbdbdab adb",
"__v" : NumberInt(0)
}
This is my query so far:
db.getCollection("videocomments").aggregate([ {"$group" : {_id:"$pauseTime", count:{$sum:1}}} ])
It returns:
{ "_id" : 480, "count" : 8 }
{ "_id" : 437, "count" : 5 }
{ "_id" : 51, "count" : 4 }
{ "_id" : 434, "count" : 4 }
{ "_id" : 750, "count" : 9 }
...
How do I proceed to limit the "_id" (i.e., pauseTime) to 50 < x < 150?
Use $lte and $gte query operator with the pauseTime
db.getCollection("videocomments").aggregate([
{ "$match": {
"pauseTime": { "$gte": 50, "$lte": 150 }
}},
{ "$group": {
"_id": "$pauseTime",
"count": { "$sum": 1 }
}}
])

mongodb aggregation $max and corresponding timestamp

I'm being challenged by the $group $max in an aggregation with MongoDB on Nodes Express app. Here is the a sample of the collection;
{"_id":"5b7e78cf022be03c35776bec",
"humidity":60,
"pressure":1014.18,
"temperature":26.8,
"light":2464,
"timestampiso":"2018-08-23T09:05:19.112Z",
"timestamp":1535015119112
},
{
"_id":"5b7e7892022be03c35776bea",
"humidity":60.4,
"pressure":1014.14,
"temperature":26.7,
"light":2422,
"timestampiso":"2018-08-23T09:04:18.115Z",
"timestamp":1535015058115
},
{
"_id":"5b7e7855022be03c35776be8",
"humidity":60.6,
"pressure":1014.2,
"temperature":26.6,
"light":2409,
"timestampiso":"2018-08-23T09:03:17.113Z",
"timestamp":1535014997113
}]
What I'm trying to do is to query the collection, by first retrieving the entries of the last hour based on the timestamp and then looking for highest pressure of the sample (should be 60 entries as there is one entry per minute)
What I can de is find this value. What I'm stuggling on to have the timestamp related to that max value.
When I run
db.collection("ArduinoSensorMkr1000").
aggregate([{ "$match" : {"timestamp" : {"$gte" : (Date.now()-60*60*1000)}}},
{ "$group" : {"_id" : null, maxpressure : {"$max" : "$pressure"}
}
},
{
"$project" : { "_id" : 0 }
}
])
Fine, the output is correct and I get the maxpressure as so
[{"maxpressure":1014.87}]
but what I'm trying to output is the maxpressure field but with it, its corresponding timestamp. The output should look as so
[{"maxpressure":1014.87,"timestamp":1535015058115}]
Any hints on how I get this timestamp value to show?
Thank you for your support
You can try this first need to sort your data using $sort and you can pick max value by using $first
QUERY
db.col.aggregate([
{ "$match": { "timestamp": { "$gte": (Date.now() - 60 * 60 * 1000) } } },
{ "$sort": { "pressure": -1 } },
{
"$group": {
"_id": null, "maxpressure": { "$first": "$pressure" },
"timestamp": { "$first": "$timestamp" }
}
},
{
"$project": { "_id": 0 }
}
])
DATA
[{
"_id" : "5b7e78cf022be03c35776bec",
"humidity" : 60.0,
"pressure" : 1014.18,
"temperature" : 26.8,
"light" : 2464.0,
"timestampiso" : "2018-08-23T09:05:19.112Z",
"timestamp" : 1535015119112.0
},
{
"_id" : "5b7e7892022be03c35776bea",
"humidity" : 60.4,
"pressure" : 1014.14,
"temperature" : 26.7,
"light" : 2422.0,
"timestampiso" : "2018-08-23T09:04:18.115Z",
"timestamp" : 1535015058115.0
},
{
"_id" : "5b7e7855022be03c35776be8",
"humidity" : 60.6,
"pressure" : 1014.2,
"temperature" : 26.6,
"light" : 2409.0,
"timestampiso" : "2018-08-23T09:03:17.113Z",
"timestamp" : 1535014997113.0
}]
THE OUTPUT
{
"maxpressure" : 1014.87,
"timestamp" : 1535015058115.0
}
My suggestion is to use sort/limit instead of grouping. By this way you can get entire document before project only interesting fields :
db['ArduinoSensorMkr1000'].aggregate(
[{ "$match" : {"timestamp" : {"$gte" : (Date.now()-5*60*60*1000)}}},
{$sort:{pressure:-1}},
{$limit:1},{
"$project" : { "_id" : 0,"timestamp":1,"pressure":1 }}
])

Mongo db project a field not in the group

I'm wondering if I can project field is not exist in the group.
For example I have the below collections and I want the name of students who has highest soccer across all students
{ "_id" : 1, "Snmae" : Alex, "score" : 97}
{ "_id" : 2, "Snmae" : Sara, "socre" : 97 }
{ "_id" : 3, "Snmae" : Sam, "socre" : 93 }
{ "_id" : 4, "Snmae" : Dan, "socre" : 77 }
db.stuudent.aggregate(
{$project:{_id:0,sname:1,score:1}},
{ $group : { _id : "", High_Score: { $max: "$score" }}}
);
The desire output is
Sname: Alex , score: 97
Sname: Sara , score: 97
Data:
{ "_id" : 1.0, "Sname" : "Alex", "score" : 97.0 },
{ "_id" : 2.0, "Sname" : "Sara", "score" : 97.0 },
{ "_id" : 3.0, "Sname" : "Sam", "score" : 93.0 },
{ "_id" : 4.0, "Sname" : "Dan", "score" : 77.0 }
Query:
db.collection.aggregate([
{
$group: {
_id: "$score",
"names": { $push: "$Sname" }
}
},
{ $sort: { "_id": -1 } },
{ $limit: 1},
{ $unwind: "$names" },
{
$project: {
"Sname": "$names",
"score": "$_id",
"_id": 0
}
}
])
Explanation:
$group - groups the students by score.
$sort - sorts the documents by score in the descending direction.
$limit - takes only first document (document with highest score value).
$unwind - splits "names" array into separated documents.
$project - generates the final results (documents with defined shape).

Mongo db skip-limit work before match after unwind

This is my query:
db.getCollection('grades').
aggregate([{ "$match" : { "class_id" : 28, "student_id" : 0 } },
{ "$unwind" : "$scores" },
{ "$match" : { "scores.type" : "homework" } },
{ "$skip" : 3 }, { "$limit" : 3 },
{ "$group" : { "_id" : { "id" : "$_id" }, "scores" : { "$push" : "$scores" } } },
{ "$project" : { "_id" : "$_id.id", "scores" : 1 } }])
scores - is a nested array of objects. Score object - {type: "someType", score: someScore}. This query returns one document.
The problem: array of scores has 6 objects and 4 of them have type homework.
The result, what I've received: http://prntscr.com/bq217r
The original document: http://prntscr.com/bq23bv
Why skip-limit performed before match operator? How can I fix it?
As per attached screenshot everything looks OK.
we have 4 elements 1 2 3 4, then we are skipping 3, so we get 4 at the end... and 53 is the value :-)
btw your skip/limit is after $match

mongodb aggregation find min value and other fields in nested array

Is it possible to find in a nested array the max date and show its price then show the parent field like the actual price.
The result I want it to show like this :
{
"_id" : ObjectId("5547e45c97d8b2c816c994c8"),
"actualPrice":19500,
"lastModifDate" :ISODate("2015-05-04T22:53:50.583Z"),
"price":"16000"
}
The data :
db.adds.findOne()
{
"_id" : ObjectId("5547e45c97d8b2c816c994c8"),
"addTitle" : "Clio pack luxe",
"actualPrice" : 19500,
"fistModificationDate" : ISODate("2015-05-03T22:00:00Z"),
"addID" : "1746540",
"history" : [
{
"price" : 18000,
"modifDate" : ISODate("2015-05-04T22:01:47.272Z"),
"_id" : ObjectId("5547ec4bfeb20b0414e8e51b")
},
{
"price" : 16000,
"modifDate" : ISODate("2015-05-04T22:53:50.583Z"),
"_id" : ObjectId("5547f87e83a1dae00bc033fa")
},
{
"price" : 19000,
"modifDate" : ISODate("2015-04-04T22:53:50.583Z"),
"_id" : ObjectId("5547f87e83a1dae00bc033fe")
}
],
"__v" : 1
}
my query
db.adds.aggregate(
[
{ $match:{addID:"1746540"}},
{ $unwind:"$history"},
{ $group:{
_id:0,
lastModifDate:{$max:"$historique.modifDate"}
}
}
])
I dont know how to include other fields I used $project but I get errors
thanks for helping
You could try the following aggregation pipeline which does not need to make use of the $group operator stage as the $project operator takes care of the fields projection:
db.adds.aggregate([
{
"$match": {"addID": "1746540"}
},
{
"$unwind": "$history"
},
{
"$project": {
"actualPrice": 1,
"lastModifDate": "$history.modifDate",
"price": "$history.price"
}
},
{
"$sort": { "lastModifDate": -1 }
},
{
"$limit": 1
}
])
Output
/* 1 */
{
"result" : [
{
"_id" : ObjectId("5547e45c97d8b2c816c994c8"),
"actualPrice" : 19500,
"lastModifDate" : ISODate("2015-05-04T22:53:50.583Z"),
"price" : 16000
}
],
"ok" : 1
}