问题
I am implementing a backend using Mongoose and MongoDB with "user" documents such as this:
> db.users.find().pretty()
{
"_id" : ObjectId("5c46eb642c825626124b1e3c"),
"username" : "admin",
"searches" : [
ISODate("2019-01-30T14:52:07Z"),
ISODate("2019-01-30T14:53:40Z"),
ISODate("2019-01-30T14:54:48Z"),
ISODate("2019-02-03T17:11:57Z"),
ISODate("2019-02-04T06:40:00Z")
]
}
The searches field is an array logging the time when the user run some search functionality. I want to select a username and compute how many searches were run in the last hour, day, and in total. My problem is getting these three values in one query.
I am using aggregation to select the user, extract the searches with unwind, query on time e.g. dates greater than one hour ago, and count the results.
>let now = new Date()
ISODate("2019-02-04T06:56:29.095Z")
>let onehourago = new Date(now.getTime() - 1000 * 3600);
>let yesterday = new Date(now.getTime() - 1000 * 3600 * 24);
>let queryUser = { $match: {username: "admin"}};
>let unwind = { $unwind : "$searches" };
>let queryTime = { $match: {searches: {$gte: onehourago}}};
>let counter = {$count: "lasthour"};
>db.users.aggregate([queryUser, unwind, queryTime, counter])
{ "lasthour" : 1 }
I would like to get:
{ "lasthour" : 1, "today": 2, "total": 5 }
Bonus point if the query returns 0 instead of empty when there is no match (but I can work around that in javascript).
回答1:
You can use $filter aggregation to filter out the searches
array
db.collection.aggregate([
{ "$match": { "username": "admin" }},
{ "$project": {
"total": { "$size": "$searches" },
"lasthour": {
"$size": {
"$filter": {
"input": "$searches",
"as": "search",
"cond": {
"$and": [
{ "$gte": ["$$search", onehourago] },
{ "$lte": ["$$search", now] }
]
}
}
}
},
"today": {
"$size": {
"$filter": {
"input": "$searches",
"as": "search",
"cond": {
"$and": [
{ "$gte": ["$$search", yesterday] },
{ "$lte": ["$$search", now] }
]
}
}
}
}
}}
])
来源:https://stackoverflow.com/questions/54511628/fitler-nested-array-using-lte-gte