Mongodb need count for specific member id per day - mongodb

Collection name : activity
What I need is activity count
of "memberId" = 123
where activity "type" = 'xxx'
per day
between "11/01/2015" and "11/15/2015" // from date and to date range
Expected Output:
[
{date:"2015-02-22",count:10},
{date:"2015-02-22",count:5},
]
I have no idea how to perform aggregate between dates and for a specific member id
where I am at is far far away from the solution :
db.activity.aggregate(
{ $project: {
date: {
years: {$year: '$dateInserted'},
months: {$month: '$dateInserted'},
days: {$dayOfMonth: '$dateInserted'},
},
memberId: '$memberId'
}},
{ $group: {
_id: { memberId: '$memberId', date: '$date' },
number: { $sum: 1}
}})

db.activity.aggregate([
{$match : { memberId : "xxx",item:"xyz",dateInserted: {$gte: ISODate("2013-01-01T00:00:00.0Z"), $lt: ISODate("2016-02-01T00:00:00.0Z")}}},
{$project: {day: {day: {$dayOfMonth: '$dateInserted'}, month: {$month: '$dateInserted'}, year: {$year: '$dateInserted'}}}},
{$group: { _id: { day: '$day' }, count: { $sum: 1} }},{ $sort:{_id:1}}
]);
Try that

You may need add $match stage before $project:
$match:
{dateInserted:{{$gte:new Date("2015-01-11T00:00:00 -02:00"),{$lte:new Date("2015-01-15T23:59:59 -02:00")}}},
{memberId:123},
{type:"xxx"}

Related

Mongodb: how to sum at breaks in 2 fields?

I have a document sample as follows:
{
_id: ObjectId("5dfa4f7b9254a519a5c7f166"),
Date: "12/11/19",
Description: "Amazon",
Amount: 32.01,
DebitCredit: "debit",
Category: "Shopping",
Month: 12,
Day: 11,
Year: 2019,
Account_Name: "Gold Delta SkyMiles"
}...
This is my query:
db.checks.aggregate([
{ $match: { Category: "Shopping" } },
{ $project: { Year: 1, Month: 1, Category: 1, Amount: { $sum: "$Amount" } } },
{
$group: {
_id: {
Year: "$Year",
Month: "$Month",
Category: "$Category",
Amount: { $sum: "$Amount" }
}
}
},
{ $sort: { Year: 1, Month: 1 } }
]);
I'm looking for a total by each year / month combination. How can I achieve this?
You're almost there, you just need to tweak your $group stage a little:
From the docs:
Groups input documents by the specified _id expression and for each distinct grouping
So all we have to do is take out the amount field outside of the _id field.
{
$group: {
_id: {
Year: "$Year",
Month: "$Month",
},
Amount: { $sum: "$Amount" }
}
}
I removed category as it was redundant but feel free to add it back to your query.
EDIT:
For the $sort stage the fields Year & Month do not exists after the $group which is the reason its failing.
After the $group stage your documents are of the form:
{
_id: {Year: number, Month: number},
Amount: number
}
So just change your $sort into:
{ $sort: { '_id.Year': 1, '_id.Month': 1 } }

MongoDB Aggregation by Shifted Date

Is there a way to aggregate by day, but over a 24 hour period that does not go from 12am - 11:59pm? A sample document looks like this:
{
date: ISODate("2012-11-02T17:04:11.102Z"),
user: 'testUser',
orders: 50
}
I need to aggregate the # of orders per user per day between 5 pm and 4:59:59.999 pm the next day. I can get the # of orders per user per day (over a 2 day range) using this:
db.hs.aggregate([{
$match: {
user: 'testUser',
date: {
$gte: new Date(2015,0,4,17,0,0,0),
$lt: new Date(2015,0,6,17,0,0,0)
}
}
}, {
$group: {
_id: {
date: {
month: {$month: "$date"},
day: {$dayOfMonth: "$date"},
year: {$year: "$date"}
},
user: "$user",
},
totord: {$sum: "$orders"}
}
}])
But this returns 3 results, one for Jan 4 after 5pm, one for Jan 5 all day, and one for Jan 6 before 5pm. I just don't know how to shift the aggregation to be between 5pm - 4:59pm.
I believe that you could use the $add aggregation operator on your dates in a $project aggregation step to get the desired result.
db.hs.aggregate([
{
$match: {
user: 'testUser',
date: {
$gte: new Date(2015,0,4,17,0,0,0),
$lt: new Date(2015,0,6,17,0,0,0)
}
}
}, {
$project: {
orders: 1,
user: 1,
date: { $add: [ "$date", 7*60*60000 ] }
}
}, {
$group: {
_id: {
date: {
month: { $month: "$date" },
day: { $dayOfMonth: "$date" },
year: { $year: "$date" }
},
user: "$user"
},
totord: {$sum: "$orders"}
}
}
])
I believe this should add 7 hours to the $date which should make it so anything after 5PM ends up after midnight the next day.

Grouping by two fields in MongoDB?

I am attempting to get a count of records created on each day for the last 15 days. I came up with the query below:
db.users.aggregate(
{ $group: {
_id: {$dayOfYear: '$created'},
created: {$sum:1},
date: {$first: '$created'}
}
},
{$sort: {_id: 1}},
{$limit: 15}
);
Which almost works, but it will also count days from exactly a year ago. So if 2 records were created on 2/20/2014 and 3 were created on 2/20/2013 then a count of 5 would be returned (when all I want is 2). I was hoping to also group by the year like below:
db.users.aggregate(
{ $group: {
_id: {{$dayOfYear: '$created'},{$year: '$created'}},
created: {$sum:1},
date: {$first: '$created'}
}
},
{$sort: {_id: 1}},
{$limit: 15}
);
But this is a syntax error. How should I be attempting to count records created on a specific day?
db.users.aggregate(
{ $group: {
_id: {
day: { $dayOfYear: '$created' },
year: { $year: '$created' }
},
count: { $sum: 1 },
date: { $first: '$created' }
}
},
{ $project: { _id: 0, date: 1, count: 1 } }, // Only for more clear result.
{ $sort: { date: -1 } }, // If you want to view last 15 days - sort by descending.
{ $limit: 15 }
);

Is it possible to type cast data inside an aggregation pipeline on MongoDB?

When I need to aggregate things by date using the aggregate command on MongoDB, I usually do this:
db.mycollection.aggregate(
{
$project: {
day: {$dayOfMonth: "$date"},
mon: {$month: "$date"},
year: {$year: "$date"},
}
},
{
$group: {
_id : {day: "$day", mon: "$mon", year: "$year"},
count: {$sum: 1}
}
}
)
and eventually concatenate the day, mon, and year fields into a date string in the application. For many reasons though, sometimes I want to concatenate the fields before leaving the database, so I initially tried:
db.mycollection.aggregate(
{
$project: {
day: {$dayOfMonth: "$date"},
mon: {$month: "$date"},
year: {$year: "$date"},
}
},
$project: {
datestr: {
$concat : ["$year", "-", "$month", "-", "$day"]
}
}
},
{
$group: {
_id : {day: "$day", mon: "$mon", year: "$year"},
count: {$sum: 1}
}
}
)
This won't work because $concat expects strings and day, mon and year are integers. So, my question is: can I type cast a field with the $project operation?
Yes, you can use $substr for casting a number to a string. Your missing link would look like:
{
$project: {
day_s: { $substr: [ "$day", 0, 2 ] },
mon_s: { $substr: [ "$month", 0, 2 ] },
year_s: { $substr: [ "$year", 0, 4 ] }
}
}

mongodb group every 2 weeks

This is how to group data weekly :
transactions.aggregate({
[
{$match: {status: "committed"}},
{$group: {
_id: {
$year: "$date",
$week: "$date"
},
count: {$sum: 1},
start_date: {$min: "$date"},
end_date: {$max: "$date"}
}}
]
});
The question is, how about grouping every 2 weeks and get the count?
Thank you.
CORRECT WAY ACCORDING TO ACCEPTED ANSWER
Thanks to Mzzl, this works for grouping every 2 weeks. Below is the complete version.
db.transactions.aggregate([
{$match: {status: "committed"}},
{$project: {
twoweekperiod: {
$subtract: [
{$week: "$date"}, {$mod: [{$week: "$date"}, 2] }
]
},
date:1,
status:1
}},
{$group: {
_id: {
year: {$year: "$date"},
twoweek: "$twoweekperiod"
},
count: {$sum: 1},
start_date: {$min: "$date"},
end_date: {$max: "$date"}
}}
])
Assuming $week contains the week number, you can create an 'every two weeks' number, and group by that. Try something like this:
{
$project: {
twoweekperiod: {
$subtract: [
'$week', {$mod: ['$week', 2] }
]
}, status:1, date:1, etc...
}
}
I don't know of a way to do an integer divide in a mongo query, so instead I subtract weeknumber mod 2 from the weeknumber, to get a number that changes every other week instead of every week. You could then try grouping by this number.