I have this simple collection of views:
Views:
[
{
title: "cartoons",
views: 1,
created_at: 2022-10-03 12:00:00.000Z
},
{
title: "songs",
views: 4,
created_at: 2022-10-04 12:00:00.000Z
},
{
title: "lectures",
views: 3,
created_at: 2022-10-10 12:00:00.000Z
},
{
title: "news",
views: 2,
created_at: 2022-10-05 12:00:00.000Z
},
{
title: "movies",
views: 6,
created_at: 2022-10-07 12:00:00.000Z
},
{
title: "tv series",
views: 6,
created_at: 2022-10-12 12:00:00.000Z
}
]
Here I need to see how many views I got on each day of week in e.g 2 years
Expected Result:
{
"monday": 4,
"tuesday": 4,
"wednesday": 8,
"thursday": 0,
"friday": 6,
"saturday": 0,
"sunday": 0,
}
Since I am very new to mongodb, Is this possible to perform such operation using query? If yes then can I get some help regarding this?
What about this?
// select some random mongo database for testing
use("stack")
// at first clean collection
db.data.drop()
// populate with initial data
db.data.insertMany([
{
title: "cartoons",
views: 1,
created_at: ISODate("2022-10-03 12:00:00.000Z"),
},
{
title: "songs",
views: 4,
created_at: ISODate("2022-10-04 12:00:00.000Z"),
},
{
title: "lectures",
views: 3,
created_at: ISODate("2022-10-10 12:00:00.000Z"),
},
{
title: "news",
views: 2,
created_at: ISODate("2022-10-05 12:00:00.000Z"),
},
{
title: "movies",
views: 6,
created_at: ISODate("2022-10-07 12:00:00.000Z"),
},
{
title: "tv series",
views: 6,
created_at: ISODate("2022-10-12 12:00:00.000Z"),
}
])
// get results
p = [
// get day of week for each record based on created_at date
{
$project: {
weekDay: {
$arrayElemAt: [
// mongo returns day numbers from 1 to 7, Sunday being 1
["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"],
{ $add: [ {$dayOfWeek: "$created_at"}, -1 ] }
]
},
views: 1,
_id: 0,
}
},
// count sum of views numbers for each weekday
{
$group: { _id: "$weekDay", total_views: {$sum: "$views"} }
},
// reshape current results to make them easily convertable to one final object
{
$replaceRoot: {
newRoot: { k: "$_id", v: "$total_views" }
}
},
// step required to get just 1 document at the end
{
$group: {
_id: 0,
merged: { $push: "$$ROOT" }
}
},
// fill in missing week days with 0 values and follow sorting order that we want
{
$project: {
merged: {
$mergeObjects: [
{
"monday": 0,
"tuesday": 0,
"wednesday": 0,
"thursday": 0,
"friday": 0,
"saturday": 0,
"sunday": 0,
},
{$arrayToObject: "$merged"},
]
}
}
},
// return field value that we want directly
{
$replaceRoot: { newRoot: "$merged"}
}
]
// Run
db.data.aggregate(p)
And the result is
[
{
"monday": 4,
"tuesday": 4,
"wednesday": 8,
"thursday": 0,
"friday": 6,
"saturday": 0,
"sunday": 0
}
]
https://mongoplayground.net/p/QutCGjKiy6z
await db.collectionName.aggregate([{
$addFields: {
days: {
$dayOfWeek: {
$toDate: '$created_at'
}
}
}
}, {
$group: {
_id: {
days: '$days'
},
totalReview: {
$sum: '$views'
},
daysCount: {
$sum: 1
}
}
}, {
$project: {
_id: 0,
totalReview: 1,
day: {
$switch: {
branches: [
{
'case': {
$eq: [
'$_id.days',
1
]
},
then: 'sunday'
},
{
'case': {
$eq: [
'$_id.days',
2
]
},
then: 'monday'
},
{
'case': {
$eq: [
'$_id.days',
3
]
},
then: 'tuesday'
},
{
'case': {
$eq: [
'$_id.days',
4
]
},
then: 'wednesday'
},
{
'case': {
$eq: [
'$_id.days',
5
]
},
then: 'thursday'
},
{
'case': {
$eq: [
'$_id.days',
6
]
},
then: 'friday'
},
{
'case': {
$eq: [
'$_id.days',
7
]
},
then: 'saturday'
}
],
'default': 'day unknown'
}
}
}
}]);
You can do it like this:
$set and $isoDayOfWeek - to calculate the day of week based on created_at property
$group and $sum - to sum all views for each day of the week
db.collection.aggregate([
{
"$set": {
"dayOfWeek": {
"$isoDayOfWeek": "$created_at"
}
}
},
{
"$group": {
"_id": "$dayOfWeek",
"count": {
"$sum": "$views"
}
}
}
])
Note: In the response, 1 is Sunday and 7 is Saturday.
Working example
Related
I have this mongoose query:
MinutesSpentStudying.aggregate([
{ $match: { connected_user_id: ObjectId(user_id) } },
{
$project: {
minutes_spent_studying: 1,
year: { $year: "$date" },
day: { $dayOfMonth: "$date" },
},
},
{
$group: {
_id: {
day: "$day",
year: "$year",
},
total_minutes: { $sum: "$minutes_spent_studying" },
},
},
{ $sort: { _id: 1 } },
]);
It returns this response:
[
{
"_id": {
"day": 2,
"year": 2021
},
"total_minutes": 11
},
{
"_id": {
"day": 3,
"year": 2021
},
"total_minutes": 1
},
{
"_id": {
"day": 26,
"year": 2020
},
"total_minutes": 1
},
{
"_id": {
"day": 27,
"year": 2020
},
"total_minutes": 3
},
]
I'd like it to sort out by year, and then by day so that it returns the results of 2020 and then the result of 2021.
Any idea how to configure so as to achieve this result?
You can sort by multiple fields and use the dot notation for the nested ones:
{
$sort: {
"_id.year": 1,
"_id.day": 1
}
}
Mongo Playground
Collection of my database is something like below
[{
_id:1,
status:"active",
sale: 4,
createdAt:"2019-10-08 08:46:19"
},
{
_id:2,
status:"inactive",
sale:5,
createdAt:"2019-10-08 06:41:19"
},
{
_id:2,
status:"inactive",
sale:5,
createdAt:"2019-10-08 02:01:19"
}]
I need to group it by "day".The result which I want
[{
createdAt:"2019-10-08 02:01:19",
inactive: 2,
active:1,
salesOfActive: 4,
salesOfInactive:10
}]
I am not getting the actual result which I want any help will be highly appreciated
I had try with this but won't get an idea how i will get salesOfActive and salesOfInactive per day
{
$group: {
_id: {
day: { $dayOfMonth: "$createdAt" }
},
inActive:{$sum: { status:"inactive"}},
active:{$sum: { status:"active"}},
salesOfActive: { $sum:$sale }
}
}
Basically you need to $sum each field $conditionally here
db.collection.aggregate([
{ "$group": {
"_id": {
"$dayOfMonth": { "$dateFromString": { "dateString": "$createdAt" } }
},
"inactive": {
"$sum": { "$cond": [{ "$eq": ["$status", "inactive"] }, 1, 0] }
},
"active": {
"$sum": { "$cond": [{ "$eq": ["$status", "inactive"] }, 0, 1] }
},
"salesOfInactive": {
"$sum": { "$cond": [{ "$eq": ["$status", "inactive"] }, "$sale", 0] }
},
"salesOfActive": {
"$sum": { "$cond": [{ "$eq": ["$status", "inactive"] }, 0, "$sale"] }
}
}}
])
MongoPlayground
Im currently having an almost working aggregate query, that would get the users array, and order the objects there by their score.
But not getting the expected output, for some reason the entire family data is beeing printed again.
How do i fix this?
Executed code:
return Family.aggregate([
// Initial document match (uses index, if a suitable one is available)
{ $match: {name: 'Management'}},
// Expand the scores array into a stream of documents
{ $unwind: '$users' },
// Sort in descending order
{ $sort: {
'users.score': -1
}}]
Current result:
{ _id: 5c8e5c79e55ef42ce4923e0b,
name: 'Management',
time_started: 1552833657354,
location: 1,
isFamily: true,
last_member: 0,
score: 0,
users:
{ userid: '5c852292d1bd911abc4957dc',
joined_date: 1552839246371,
permission: 5,
upgrade: 0,
score: 141,
_id: 5c8e724e6e5e6512447c1a61 },
__v: 0 },
{ _id: 5c8e5c79e55ef42ce4923e0b,
name: 'Management',
time_started: 1552833657354,
location: 1,
isFamily: true,
last_member: 0,
score: 0,
users:
{ userid: '5c8522a96bcca9268c0753fe',
joined_date: 1552833657354,
permission: 6,
upgrade: 0,
score: 32,
_id: 5c8e5c79e55ef42ce4923e0c },
__v: 0 } ]
wanted result:
{
name: 'Management',
time_started: 1552833657354,
location: 1,
isFamily: true,
last_member: 0,
score: 0,
users:
[{ userid: '5c852292d1bd911abc4957dc',
joined_date: 1552839246371,
permission: 5,
upgrade: 0,
score: 141,
_id: 5c8e724e6e5e6512447c1a61 },
__v: 0 },
{ userid: '5c8522a96bcca9268c0753fe',
joined_date: 1552833657354,
permission: 6,
upgrade: 0,
score: 32,
_id: 5c8e5c79e55ef42ce4923e0c },
__v: 0 }
]}
You need to use one more $group stage to reshape the splited array into its original form after $unwind
Family.aggregate([
{ "$match": { "name": "Management" }},
{ "$unwind": "$users" },
{ "$sort": { "users.score": -1 }},
{ "$group": {
"_id": "$_id",
"users": { "$push": "$users" },
"name": { "$first": "$name" },
"time_started": { "$first": "$time_started" },
"isFamily": { "$first": "$isFamily" },
"last_member": { "$first": "$last_member" },
"score": { "$first": "$score" },
}}
])
I am trying to write the aggregation total average duration.
I got the output but not coming all fields.
How to get all fields in the results?
Any one please suggest me.
db.lights.aggregate(
{
$match: {
CREATE_DATE: {
$gte: ISODate("2018-01-24T20:05:30.000Z"),
$lt: ISODate("2018-02-24T20:05:30.000Z")
}
}
},{ $addFields: {
offduration: {
$divide: [
{ $subtract: ["$RECEIVEDDATE", "$CREATE_DATE"] },
3600000
]
}
}
}, { "$group": {
_id: {
SWITCHID: "$SWITCHID",
STATUS: "$STATUS"
},
avgduration: { $avg: "$offduration" },
SWITCHID: { $first: "$SWITCHID" },
CREATE_DATE: { $first: "$CREATE_DATE" },
RECEIVEDDATE: { $first: "$RECEIVEDDATE" },
STATUS: { $first: "$STATUS" },
offduration: { $first: "$offduration" },
} },
{ $project: {
_id: 0,
SWITCHID: 1,
CREATE_DATE: 1,
RECEIVEDDATE: 1,
STATUS: 1,
avgduration: '$avgduration',
offduration: '$offduration'
} },
{"$group" : {
_id: { SWITCHID: "$SWITCHID" },
on_minus_off: {
$sum:{ "$cond": [
{ "$eq": ["$STATUS", "LIGHTS OFF"] },
"$avgduration",
{ $subtract: [ 0, "$avgduration" ] }
]
}
}
}
}
)
You want to add "$project" for the required field in the first pipeline. then you want to apply in $group pipeline like this,
$project: {
requireFiled1 : "$requireFiled1",
requireFiled2 : "$requireFiled2", }
// And add the below in $group
requiredField1 : {
$first: "$requiredField1" // Projected Name in Projection Section
},
db.lights.aggregate({
$match: {
CREATE_DATE: {
$gte: ISODate("2018-01-24T20:05:30.000Z"),
$lt: ISODate("2018-02-24T20:05:30.000Z")
}
}
},
{
$addFields: {
offduration: {
$divide: [
{
$subtract: [
"$RECEIVEDDATE",
"$CREATE_DATE"
]
},
3600000
]
}
}
},
{
"$group": {
_id: {
SWITCHID: "$SWITCHID",
STATUS: "$STATUS"
},
avgduration: {
$avg: "$offduration"
},
SWITCHID: {
$first: "$SWITCHID"
},
CREATE_DATE: {
$first: "$CREATE_DATE"
},
RECEIVEDDATE: {
$first: "$RECEIVEDDATE"
},
STATUS: {
$first: "$STATUS"
},
offduration: {
$first: "$offduration"
},
}
},
{
$project: {
_id: 0,
SWITCHID: 1,
CREATE_DATE: 1,
RECEIVEDDATE: 1,
STATUS: 1,
avgduration: '$avgduration',
offduration: '$offduration'
}
},
{
"$group": {
_id: {
SWITCHID: "$SWITCHID"
},
requireFiled1 : {
$first: "$requireFiled1"
},
on_minus_off: {
$sum: {
"$cond": [
{
"$eq": [
"$STATUS",
"LIGHTS OFF"
]
},
"$avgduration",
{
$subtract: [
0,
"$avgduration"
]
}
]
}
}
}
})
Given the following data set of Event objects:
[
{
"_id": ObjectId("4fda05cb322b1c95b531ac26",
"title": "BUTTON CLICKED",
"createdAt": ISODate("2017-01-12T01:00:00+01:00")
},
{
"_id": ObjectId("1235h1k235h1kl325h1v31gv",
"title": "BUTTON CLICKED",
"createdAt": ISODate("2017-01-14T01:00:00+01:00")
},
{
"_id": ObjectId("c2n890904cn897qnxp23hjk1",
"title": "PAGE VIEWED",
"createdAt": ISODate("2017-01-12T02:00:00+01:00")
}
]
How would I group them by date then by name?
The desired result would look like this:
[
{
_id: { year: 2017, month: 1, day: 11 },
events: [ {
title: "BUTTON PRESSED",
count: 3
}, {
title: "PAGE VIEWED",
count: 2
}
]
},
{
_id: { year: 2017, month: 1, day: 24 },
events: [ {
title: "BUTTON PRESSED",
count: 1
}
]
}
]
Any help on this issue would be greatly appreciated, so thank you!
you can try this query
db.collectionName.aggregate([
$group: {
_id : {
year : { $year : "$createdAt" },
month : { $month : "$createdAt" },
day : { $dayOfMonth : "$createdAt" },
title: "$title"
},
count:{$sum:1}
}
},
{
$group:{
_id:{
year: "$_id.year",
month: "$_id.month",
day: "$_id.day"
},
data:{
$push: {
name:"$_id.title",
count:"$count"
}
}
}
}
])