I have 2 collections
1st users and 2nd shifts
When I am writing a query like below with lookup and unwind expressions.
results.users = await model.aggregate([
{
$match: filter,
},
{
$lookup: {
from: "shifts",
localField: "_id",
foreignField: "employeeId",
as: "shifts",
},
},
{
$set: {
shifts: {
$filter: {
input: "$shifts",
cond: [
{
$and: [
{
$gte: [
"$$this.date",
new Date("2022-10-01"),
],
},
{
$lte: [
"$$this.date",
new Date("2022-10-05"),
],
},
],
},
],
},
},
},
},
]);
[
{
_id: "60dd781c4524e6c116e2336d",
workerFirstName: "MADASWAMY",
workerSurname: "KARUPPASWAMY",
workerId: "1002",
shifts:[]
},
{
_id: "60dd781d4524e6c116e234d4",
workerFirstName: "AMIT",
workerSurname: "SHAH",
workerId: "1001",
shifts:[]
},
{
_id: "60dd781d4524e6c116e23642",
workerFirstName: "DEVELOPER",
workerSurname: "DEVELOPER",
workerId: "7738",
shifts: [
{
_id: "634d8d3ce596dd34c9532d5d",
month: "October",
workerId: "7738",
date: "2022-10-01T00:00:00.000Z",
},
{
_id: "634d8d3ce596dd34c9532d5d",
month: "October",
workerId: "7738",
date: "2022-10-02T00:00:00.000Z",
},
{
_id: "634d8d3ce596dd34c9532d5d",
month: "October",
workerId: "7738",
date: "2022-10-03T00:00:00.000Z",
},
{
_id: "634d8d3ce596dd34c9532d5d",
month: "October",
workerId: "7738",
date: "2022-10-04T00:00:00.000Z",
},
{
_id: "634d8d3ce596dd34c9532d5d",
month: "October",
workerId: "7738",
date: "2022-10-05T00:00:00.000Z",
},
{
_id: "634d8d3ce596dd34c9532d5d",
month: "October",
workerId: "7738",
date: "2022-10-06T00:00:00.000Z",
},
....
],
},
]
As you can see I am getting, the list of Data.
but I want only specific data between the date range given
Ex : - The date range is from 1 to 5th Oct so I want only that much data but I am getting all data.
i tried doing this and it worked for me
{
$set: {
attendances: {
$filter: {
input: "$attendances",
cond: {
$and: [
{
$gte: ["$$this.Date", new Date(fromDate)],
},
{
$lte: ["$$this.Date", new Date(toDate)],
},
{
$eq: ["$$this.createdAs", dataType],
},
{
$eq: ["$$this.status", true],
},
{
$eq: ["$$this.workerType", workerType],
},
],
},
},
},
},
},
Just removed the array brackets from the condition
Related
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
I have the following document structure
{
"_id": "60b7b7c784bd6c2a1ca57f29",
"user": "607c58578bac8c21acfeeae1",
"exercises": [
{
"executed_reps": [8,7],
"_id": "60b7b7c784bd6c2a1ca57f2a",
"exercise_name": "Push up"
},
{
"executed_reps": [5,5],
"_id": "60b7b7c784bd6c2a1ca57f2b",
"exercise_name": "Pull up"
}
],
}
In aggregation, I am trying to sum all the executed_reps so the end value in this example should be 25 (8+7+5+5).
Here is the code I have so far:
const exerciseStats = await UserWorkout.aggregate([
{
$match: {
user: { $eq: ObjectId(req.query.user) },
},
},
{ $unwind: '$exercises' },
{
$group: {
_id: null,
totalReps: {
$sum: {
$reduce: {
input: '$exercises.executed_reps',
initialValue: '',
in: { $add: '$$this' },
},
},
},
},
},
]);
This gives a result of 5 for totalReps. What am I doing wrong?
Well 10 minutes later I found the solution myself:
UserWorkout.aggregate([
{
$match: {
user: { $eq: ObjectId(req.query.user) },
},
},
{ $unwind: '$exercises' },
{
$project: {
total: { $sum: '$exercises.executed_reps' },
},
},
{
$group: {
_id: null,
totalExercises: { $sum: '$total' },
},
},])
Had to use $project first. :)
You can do it like this:
const exerciseStats = await UserWorkoutaggregate([
{
"$addFields": {
"total": {
"$sum": {
"$map": {
"input": "$exercises",
"as": "exercise",
"in": {
"$sum": "$$exercise.executed_reps"
}
}
}
}
}
}
])
Here is the working example: https://mongoplayground.net/p/5_fsPgSh8EP
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
I'm trying to fetch all latest messages between User A and any other user.
I keep running into the error ,
The field name '$acknowledged' cannot be an operator name
Not sure what I'm doing wrong here. Mongo playground.
The expected output should be the latest message exchanged between user with id 5a934e000102030405000001, and any other user.
[
{
"from": ObjectId("5a934e000102030405000002"),
"to": ObjectId("5a934e000102030405000001"),
"acknowledged": true,
date: "2020-04-17T18:26:34.353+00:00"
},
{
"from": ObjectId("5a934e000102030405000001"),
"to": ObjectId("5a934e000102030405000003"),
"acknowledged": false,
date: "2020-04-17T18:26:31.353+00:00"
},
{
"from": ObjectId("5a934e000102030405000004"),
"to": ObjectId("5a934e000102030405000001"),
"acknowledged": false,
date: "2020-04-17T18:26:29.353+00:00"
},
]
You had a typo here:
$acknowledged: { acknowledged: {
$first: "$acknowledged", --> $first: "$acknowledged"
}
},
and
then: "$responseTo", --> then: "$to",
db.Message.aggregate([
{
$match: {
$or: [
{
from: {
$in: [
ObjectId("5a934e000102030405000001")
]
}
},
{
to: {
$in: [
ObjectId("5a934e000102030405000001")
]
}
}
]
}
},
{
$sort: {
date: -1
}
},
{
$group: {
_id: {
userConcerned: {
$cond: [
{
$in: [
"$to",
[
ObjectId("5a934e000102030405000001")
]
]
},
"$to",
"$from"
]
},
interlocutor: {
$cond: [
{
$in: [
"$to",
[
ObjectId("5a934e000102030405000001")
]
]
},
"$from",
"$to"
]
}
},
id: {
$first: "$_id"
},
from: {
$first: "$from"
},
acknowledged: {
$first: "$acknowledged"
},
to: {
$first: "$to"
},
date: {
$first: "$date"
}
}
},
{
$lookup: {
from: "User",
localField: "to",
foreignField: "_id",
as: "to"
}
},
{
$unwind: "$to"
},
{
$lookup: {
from: "User",
localField: "from",
foreignField: "_id",
as: "from"
}
},
{
$unwind: "$from"
},
{
$project: {
_id: 0,
date: 1,
acknowledged: 1,
from: "$from._id",
to: "$to._id"
}
}
])
MongoPlayground
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"
}
}
}
}
])