$project to contain the latest date from the group - mongodb

I have a collection that is filled with messages, and I want to get a group of how many messages there are per room.
Gets messages within the last hour
Where gameId = 5550d868c5242fb3299a2604
Grouped by $room
Sorted by created
When I add the projection, the count works, but _id becomes null, and created doesn't even return.
What I am looking for is _id to contain $room, created to contain the newest date, and count to be the count of items.
db.chatMessages.aggregate([
{
$match: {
created: {
$gte: new Date((new Date()) - (1000 * 60 * 60))
},
gameId: ObjectId("5550d868c5242fb3299a2604")
}
},
{
$project: {created: 1}
},
{
$group: {
_id: "$room",
count: {$sum: 1}
}
},
{
$sort: {created: -1}
}
])
Here is some example data:
{
"gameId" : ObjectId("5550d868c5242fb3299a2604"),
"message" : "For real?",
"room" : "Main",
"name" : "Hello",
"created" : ISODate("2015-05-24T17:49:43.868Z"),
"_id" : ObjectId("55620f376aa13616759f4f06")
}
{
"gameId" : ObjectId("5550d868c5242fb3299a2604"),
"message" : "Yeah for reals...",
"room" : "Main",
"name" : "Jim",
"created" : ISODate("2015-05-24T17:49:59.135Z"),
"_id" : ObjectId("55620f476aa13616759f4f07")
}
Here is the returned output:
{
"result" : [
{
"_id" : null,
"count" : 4
}
],
"ok" : 1
}
Here is what I am looking for:
{
"result" : [
{
"_id" : "Main",
"count" : 4,
"created" : ISODate("2015-05-24T17:37:19.331Z")
}
],
"ok" : 1
}
So what is causing this to break when I add the $project?

I was able to get it by adding created to the group and doing $max on the column like this:
db.chatMessages.aggregate([
{
$project: {room: 1, created: 1}
},
{
$match: {
created: {
$gte: new Date((new Date()) - (1000 * 60 * 60 * 20000))
},
gameId: ObjectId("5550d868c5242fb3299a2604")
}
},
{
$group: {
_id: "$room",
count: {$sum: 1},
created: {$max: "$created"}
}
},
{
$sort: {created: -1}
}
])

Related

How to count total of result aggregate mongodb returns?

My query use aggregate to summary all alert group by alert type, filter by houseId.
I can count only total alert of a group.
How I can count total alert of a house ( total of all group )
db.getCollection('alerts').aggregate([{
$match: {
houseId: ObjectId("609100a56ed9f8001351aee3")
}
}, {
$group: {
_id: '$type',
count: { $sum: 1 },
alerts: {
$push: {
_id: '$_id',
type: '$type'
}
}
}
}
])
Result:
[{
"_id" : "cool",
"count" : 1.0,
"alerts" : [
{
"_id" : ObjectId("61387e740dc3d853f1eee5b0"),
"type" : "cool"
}
]
}, {
"_id" : "hot",
"count" : 2.0,
"alerts" : [
{
"_id" : ObjectId("61387e740dc3d853f1eee5b0"),
"type" : "hot"
},
{
"_id" : ObjectId("61387e740dc3d853f1eee5b0"),
"type" : "hot"
}
]
}]
I expect a field total: 2 = cool alert + hot alert

Mongo $group and $count, and then $sort the result

I have a simple table with ranked users...
User:
{
"_id" : "aaa",
"rank" : 10
},
{
"_id" : "bbb",
"rank" : 30
},
{
"_id" : "ccc",
"rank" : 20
},
{
"_id" : "ddd",
"rank" : 30
},
{
"_id" : "eee",
"rank" : 30
},
{
"_id" : "fff",
"rank" : 10
}
And I would like to count how many have each rank, and then sort them with highest to lowest count
So I can get this result:
Result:
{
"rank" : 30,
"count": 3
},
{
"rank" : 10,
"count": 2
},
{
"rank" : 20,
"count": 1
}
I tried different things but cant seem to get the correct output
db.getCollection("user").aggregate([
{
"$group": {
"_id": {
"rank": "$rank"
},
"count": { "$sum": 1 }
},
"$sort": {
"count" : -1
}
])
I hope this is possible to do.
You can count and then sort them by aggregation in mongodb
db.getCollection('users').aggregate(
[
{
$group:
{
_id: "$rank",
count: { $sum: 1 }
}
},
{ $sort : { count : -1} }
]
)
Working example
https://mongoplayground.net/p/aM3Ci3GACjp
You don't need to add additional group or count stages when you can do it in one go -
db.getCollection("user").aggregate([
{
$sortByCount: "$rank"
}
])

MongoDB get user which are new today

I am trying to find a user list which is new for day-1. I have written the query to find the users who arrived till the day before yesterday and the list of users arrived yesterday. Now I want minus those data how can I do that in a single aggregate function.
Function to get the list before yesterday
db.chat_question_logs.aggregate([
{
$match : {"createdDate":{$lte: ISODate("2020-04-29T00:00:00Z")}}
},
{
"$project" :
{
_id : 0,
"userInfo.userId":1
}
},
{
"$group": {
"_id": {userId:"$userInfo.userId"},"count": {$sum : 1}}
}
])
similarly for the day-1 is as below
db.chat_question_logs.aggregate([
{
$match : {"createdDate":{$gte: ISODate("2020-04-30T00:00:00Z"),$lte: ISODate("2020-05-01T00:00:00Z")}}
},
{
"$project" :
{
_id : 0,
"userInfo.userId":1
}
},
{
"$group": {
"_id": {userId:"$userInfo.userId"},"count": {$sum : 1}}
}
])
Result JSON are as below
/* 1 */
{
"_id" : {
"userId" : "2350202241750776"
},
"count" : 1
},
/* 2 */
{
"_id" : {
"userId" : "26291570771793121"
},
"count" : 1
},
/* 3 */
{
"_id" : {
"userId" : "2742872209107866"
},
"count" : 5
},
/* 4 */
{
"_id" : {
"userId" : "23502022417507761212"
},
"count" : 1
},
/* 5 */
{
"_id" : {
"userId" : "2629157077179312"
},
"count" : 43
}
How can I find the difference.
It sounds like what you want is to get all users created yesterday (which is the 28th in this example).
db.chat_question_logs.aggregate([
{
$match : { $and: [
{ "createdDate":{$lt: ISODate("2020-04-29T00:00:00Z")} },
{ "createdDate": {$gte: ISODate("2020-04-28T00:00:00Z") }}
] }
},
{
"$project" :
{
_id : 0,
"userInfo.userId":1
}
},
{
"$group": {
"_id": {userId:"$userInfo.userId"},"count": {$sum : 1}}
}
])
Is this what you want?
Hi found the solution which is below
I used the group and first appearance of the Id and then filter record on date which I wanted.The query is as below
db.chat_question_logs.aggregate([
{
$group:
{
_id: "$userInfo.userId",
firstApprance: { $first: "$createdDate" }
}
},
{
$match : { "firstApprance": { $gte: new ISODate("2020-05-03"), $lt: new ISODate("2020-05-05") } }
}
])

How to subtract time series element to get differance to the date before?

I am trying to build a dashboard chart in Mongo-Atlas.
The Table should should show the date on x-axis, the _id on y-axis.
The Values should be the count difference to the date before.
I have a collection with data points such as:
_id: "someName"
timestamp: 2019-09-05T06:24:24.689+00:00
count: 50
_id: "someName"
timestamp: 2019-09-04T06:24:24.689+00:00
count: 40
...
The goal is to get the difference of the count to the data point before. Having the same name.
_id: "someName"
timestamp: 2019-09-05T06:24:24.689+00:00
count: 50
difference: 10
_id: "someName"
timestamp: 2019-09-04T06:24:24.689+00:00
count: 40
difference: 17
...
That way I could make a table listing the differences
so far I created a aggregation pipeline
[
{$sort: {
"timestamp": -1
}},
{$group: {
_id: "$_id",
count: {
$push: { count: "$count", timestamp: "$timestamp" }
}
}},
{$project: {
_id: "$_id",
count: "$count",
countBefore: { $slice: [ "$count", 1, { $size: "$count" } ] }
}}
]
I was hoping to substract count and countBefore such that i get an array with the datapoints an the difference...
So I tried to follow with:
{$project: {
countDifference: {
$map: {
input: "$countBefore",
as: "before",
in: {
$subtract: ["$$before.count", "$count.count"]
/*"$count.count" seems to be the problem, since an integer works*/
}
}
}
}
}
Mongo Atlas only shows "An unknown error occurred"
I would be glad for some advice :)
The following query can get us the expected output:
db.collection.aggregate([
{
$sort:{
"timestamp":1
}
},
{
$group:{
"_id":"$id",
"counts":{
$push:"$count"
}
}
},
{
$project:{
"differences":{
$reduce:{
"input":"$counts",
"initialValue":{
"values":[],
"lastValue":0
},
"in":{
"values":{
$concatArrays:[
"$$value.values",
[
{
$subtract:["$$this","$$value.lastValue"]
}
]
]
},
"lastValue":"$$this"
}
}
}
}
},
{
$project:{
"_id":0,
"id":"$_id",
"plots":"$differences.values"
}
}
]).pretty()
Data Set:
{
"_id" : ObjectId("5d724550ef5e6630fde5b71e"),
"id" : "someName",
"timestamp" : "2019-09-05T06:24:24.689+00:00",
"count" : 50
}
{
"_id" : ObjectId("5d724550ef5e6630fde5b71f"),
"id" : "someName",
"timestamp" : "2019-09-04T06:24:24.689+00:00",
"count" : 40
}
{
"_id" : ObjectId("5d724796ef5e6630fde5b720"),
"id" : "someName",
"timestamp" : "2019-09-06T06:24:24.689+00:00",
"count" : 61
}
{
"_id" : ObjectId("5d724796ef5e6630fde5b721"),
"id" : "someName",
"timestamp" : "2019-09-07T06:24:24.689+00:00",
"count" : 72
}
{
"_id" : ObjectId("5d724796ef5e6630fde5b722"),
"id" : "someName",
"timestamp" : "2019-09-08T06:24:24.689+00:00",
"count" : 93
}
{
"_id" : ObjectId("5d724796ef5e6630fde5b723"),
"id" : "someName",
"timestamp" : "2019-09-09T06:24:24.689+00:00",
"count" : 100
}
Output:
{ "id" : "someName", "plots" : [ 40, 10, 11, 11, 21, 7 ] }
Explanation: We are pushing count for the same id into counts array and then applying $reduce operation on it to prepare a set of new values in which current value would hold difference between the current and previous value of counts array. For the very first value, the previous value is taken as zero.

MongoDB - count items using addToSet

I'm working with a collection called "submissions" that includes mission data for a game. Every time you submit your answer to the question/mission a document is saved to the submissions collection.
A typical document looks like this:
{
"_id" : ObjectId("5b0c99dffea598002fdb6ec9"),
"status" : "Accepted",
"missionAcceptanceDate" : NumberInt(1527526261),
"submissionDate" : NumberInt(1527552495),
"location" : "",
"approvalDate" : null,
"mission_id" : ObjectId("5b0c5b10fea598002fdb6ec6"),
"user_id" : ObjectId("5b0c99d0fea598002fdb6ec7")
}
I need to build a query that can determine the following:
Counts the total submissions per grouping by status between a date range,
Counts the Total number of submissions by mission_id per each grouping.
Below is what I have so far ("cutting out some info..."):
QUERY:
db.submissions.aggregate(
{ $match: {
"submissionDate": {
"$gte": NumberInt(1527901260), //Fri, 1 Jun 2018 18:00:01 PDT
"$lte": NumberInt(1530831600) //Thu, 5 Jul 2018 16:00:00 PDT
}
}
},
{$project:
{_id:1,
status: 1,
missionAcceptanceDate: 1,
submissionDate: 1,
approvalDate: 1,
user_id: 1,
mission_id: 1
}
},
{$group: {
_id: { status: "$status" },
statusTotal: { $sum: 1 },
mission_id: { $addToSet: "$mission_id" },
}
}
)
RESULT:
{
"_id" : {
"status" : "Rejected"
},
"statusTotal" : 16.0,
"mission_id" : [
ObjectId("5b0edbfafea598002fdb6f3a"),
ObjectId("5b0f0131fea598002fdb6f43"),
ObjectId("5b0eded6fea598002fdb6f3d"),
...
]
}
{
"_id" : {
"status" : "Approved"
},
"statusTotal" : 592.0,
"mission_id" : [
ObjectId("5b391cf4e177c700308dd0ef"),
ObjectId("5b36a0d172b5240030d304be"),
ObjectId("5b3558276a0f950030db1732"),
...
]
}
This is a great, but I also need to know the Total Number of Times each "mission_id" was "Rejected" or "Approved". The desired out come should look something like the following:
{
"_id" : {
"status" : "Rejected"
},
"statusTotal" : 16.0,
"mission_id" : [
...
{ mission_id: ObjectId("5b0edbfafea598002fdb6f3a"), count: 3 },
{ mission_id: ObjectId("5b0f0131fea598002fdb6f43"), count: 5},
{ mission_id: ObjectId("5b0eded6fea598002fdb6f3d"), count: 2 }
...
]
}
{
"_id" : {
"status" : "Approved"
},
"statusTotal" : 592.0,
"missionData" : [
{ mission_id: ObjectId("5b391cf4e177c700308dd0ef"), count: 23 },
{ mission_id: ObjectId("5b36a0d172b5240030d304be"), count: 45},
{ mission_id: ObjectId("5b3558276a0f950030db1732"), count: 15 }
...
]
}
I tried using $size, $sum, $count, even using a second $group with {$sum:1} for each mission_id, but just can't figure it out. Any help with this would be so much appreciated. Thank you in advance!
You need an extra grouping before your group if I understand your question correctly.
Something like
db.submissions.aggregate([
{"$match":{"submissionDate":{"$gte":NumberInt(1527901260),"$lte":NumberInt(1530831600)}}},
{"$group":{
"_id":{"status":"$status","mission_id":"$mission_id"},
"missionTotal":{"$sum":1}
}},
{"$group":{
"_id":"$_id.status",
"statusTotal":{"$sum":"$missionTotal"},
"mission_id":{"$push":{"mission_id":"$_id.mission_id","count":"$missionTotal"}}
}}
])