我想使用mongoDB和nodeJS构建在线测试应用程序。管理员可以查看用户测试历史记录(使用日期过滤器选项)。
如果我只想显示测试结果数组包含admin指定日期的用户,如何进行查询。
日期过滤器将基于来自scheduledAt.startTime的日,月,年,我认为我必须使用聚合框架来实现此目的。
假设我有以下用户文档:
{
"_id" : ObjectId("582a7b315c57b9164cac3295"),
"username" : "lalalala@gmail.com",
"displayName" : "lalala",
"testResults" : [
{
"applyAs" : [
"finance"
],
"scheduledAt" : {
"endTime" : ISODate("2016-11-15T16:00:00.000Z"),
"startTime" : ISODate("2016-11-15T01:00:00.000Z")
},
"results" : [
ObjectId("582a7b3e5c57b9164cac3299"),
ObjectId("582a7cc25c57b9164cac329d")
],
"_id" : ObjectId("582a7b3e5c57b9164cac3296")
},
{
.....
}
],
"password" : "andi",
}
testResults文档:
{
"_id" : ObjectId("582a7cc25c57b9164cac329d"),
"testCategory" : "english",
"testVersion" : "EAX",
"testTakenTime" : ISODate("2016-11-15T03:10:58.623Z"),
"score" : 2,
"userAnswer" : [
{
"answer" : 1,
"problemId" : ObjectId("581ff74002bb1218f87f3fab")
},
{
"answer" : 0,
"problemId" : ObjectId("581ff78202bb1218f87f3fac")
},
{
"answer" : 0,
"problemId" : ObjectId("581ff7ca02bb1218f87f3fad")
}
],
"__v" : 0
}
到目前为止我尝试的内容如下所示。如果我想计算总文档数,我应该更改聚合框架的哪一部分。因为在下面的查询中,totalData是按每个组而不是每个返回文档的总和。
User
.aggregate([
{
$unwind: '$testResults'
},
{
$project: {
'_id': 1,
'displayName': 1,
'testResults': 1,
'dayOfTest': { $dayOfMonth: '$testResults.scheduledAt.startTime' },
'monthOfTest': { $month: '$testResults.scheduledAt.startTime' },
'yearOfTest': { $year: '$testResults.scheduledAt.startTime' }
}
},
{
$match: {
dayOfTest: date.getDate(),
monthOfTest: date.getMonth() + 1,
yearOfTest: date.getFullYear()
}
},
{
$group: {
_id: {id: '$_id', displayName: '$displayName'},
testResults: {
$push: '$testResults'
},
totalData: {
$sum: 1
}
}
},
])
.then(function(result) {
res.send(result);
})
.catch(function(err) {
console.error(err);
next(err);
});
答案 0 :(得分:0)
你可以尝试这样的事情。添加了项目阶段,以便在传递的日期中任何结果元素匹配时保留测试结果。将此添加为管道中的第一步,您可以按照自己的方式添加分组阶段。
$ map在每个测试结果元素中应用日期传递和开始日期之间的等于比较,并生成具有true和false值的数组。 $ anyElementTrue检查此数组,并且仅当数组中至少有一个true值时才返回true。匹配阶段仅包含匹配值为true的元素。
aggregate([{
"$project": {
"_id": 1,
"displayName":1,
"testResults": 1,
"matched": {
"$anyElementTrue": {
"$map": {
"input": "$testResults",
"as": "result",
"in": {
"$eq": [{ $dateToString: { format: "%Y-%m-%d", date: '$$result.scheduledAt.startTime' } }, '2016-11-15']
}
}
}
}
}
}, {
"$match": {
"matched": true
}
}])
替代版本:
与上述版本类似,但这个版本将项目和匹配阶段合二为一。带有$ redact的$ cond用于匹配,当找到匹配时,它会保留完整的树或者丢弃它。
aggregate([{
"$redact": {
"$cond": [{
"$anyElementTrue": {
"$map": {
"input": "$testResults",
"as": "result",
"in": {
"$eq": [{
$dateToString: {
format: "%Y-%m-%d",
date: '$$result.scheduledAt.startTime'
}
}, '2016-11-15']
}
}
}
},
"$$KEEP",
"$$PRUNE"
]
}
}])