我创建了一个员工出勤应用程序,其中将出勤记录并存储在数据库中。我试图获得所有日期字段为"Present"
的计数。数据像这样存储在数据库中:
"attendances": { <YYYY-MM-DD>: "value" } pair
// The values being "Absent" or "Present" whatever the case may be.
问题是,每当我尝试用0
计算所有条目时,我都会得到"attendances": {"2019-08-28": "Present"}
的值。
谁能帮助我找出问题所在?
//架构
const Schema = mongoose.Schema;
const employeeSchema = new Schema({
name: String,
department: String,
origin: String,
employDate: String,
attendances: Object
});
module.exports= Employee = mongoose.model('Employee', employeeSchema);
route.js
router.get('/',(req,res)=>{
Employee.collection.countDocuments({"attendances.date":"present"},(err,data)=>{
if(err){
res.status(500)
res.send(err)
}else{
res.status(200)
res.json(data)
}
})
})
//存储在MongoDB中的数据
{
"_id": "5d6565236574b1162c349d8f",
"name": "Benjamin Hall",
"department": "IT",
"origin": "Texas",
"employDate": "2019-08-27",
"__v": 0,
"attendances": {
"2019-08-28": "Sick"
}
},
{
"_id": "5d6367ee5b78d30c74be90e6",
"name": "Joshua Jaccob",
"department": "Marketing",
"origin": "new york",
"employDate": "2019-08-26",
"__v": 0,
"attendances": {
"2019-08-26": "Present",
"2019-08-27": "Sick"
}
},
答案 0 :(得分:1)
如果要按嵌入式文档中的属性查找,则必须使用点符号
这将不起作用,因为您正在要求mongoo查找出勤对象等于给定对象的文档。
{ "attendances": {"2019-08-26": "Present"}}
这仅在数据库中的出勤对象仅包含
时有效{ "attendances": {"2019-08-26": "Present"}}
这意味着您询问mongoo存储的对象是否等于给定的对象,它将返回false
{ "attendances": {"2019-08-26": "Present" , "2019-08-27": "Sick"}} == { "attendances": {"2019-08-26": "Present"}}
为此,您必须使用点符号
Employee.collection.countDocuments({"attendances.2019-08-26":"Present"},(err,data)=>{
if(err){
res.status(500)
res.send(err)
}else{
res.status(200)
res.json(data)
}
})
答案 1 :(得分:0)
由于动态日期是嵌入式文档的一部分,因此,要使用正则表达式对该字段进行查询(不区分大小写的搜索),您基本上需要使用dot notation { "attendance.2019-08-28": /present/i }
,它是用{{ 3}}:
const date = "2019-08-28" // dynamic date
const query = {
["attendances." + date]: /present/i // computed property name
}
Employee.countDocuments(query, (err, data) => {
if (err){
res.status(500).send(err)
} else{
res.status(200).json(data)
}
})
请注意,可以直接在Mongoose模型上访问computed property names函数。
对于日期范围查询,例如,您要返回最近30天的出勤人数,则需要
使用聚合框架进行查询,该框架公开了countDocuments()
,$objectToArray
和$filter
之类的运算符,以供您计数。
上述运算符使您可以使用$size
将出勤文档转换为键值对数组,然后可以根据过去30天的条件以及使用{{3 }}。要获得计数,请在过滤后的数组上使用$objectToArray
运算符。
作为说明,在文档上应用$filter
{
"2019-08-26": "Present",
"2019-08-27": "Sick"
}
返回
[
{ "k": "2019-08-26", "v": "Present" },
{ "k": "2019-08-27", "v": "Sick" }
]
要过滤过去n天,您需要首先创建该范围内的日期列表,即
[
"2019-08-27",
"2019-08-26",
"2019-08-25",
...
]
可以用
在JavaScript中完成function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
return [year, month, day].join('-');
}
const listDatesForThePastDays = n => (
Array(n)
.fill(new Date())
.map((today, i) => today - 8.64e7 * i)
.map(formatDate)
)
此列表可以在$size
中用作
{ "$filter": {
"input": { "$objectToArray": "$attendances" },
"cond": {
"$and": [
{ "$in": ["$$this.k", listDatesForThePastDays(30)] },
{ "$eq": ["$$this.v", "Present"] }
]
}
} }
并应用$objectToArray
运算符以获取计数:
{ "$size": {
"$filter": {
"input": { "$objectToArray": "$attendances" },
"cond": {
"$and": [
{ "$in": ["$$this.k", listDatesForThePastDays(30)] },
{ "$eq": ["$$this.v", "Present"] }
]
}
}
} }
您的整体查询将类似于
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
return [year, month, day].join('-');
}
const listDatesForThePastDays = n => (
Array(n)
.fill(new Date())
.map((today, i) => today - 8.64e7 * i)
.map(formatDate)
)
Employee.aggregate([
{ "$addFields": {
"numberofPresentAttendances": {
"$size": {
"$filter": {
"input": { "$objectToArray": "$attendances" },
"cond": {
"$and": [
{ "$in": ["$$this.k", listDatesForThePastDays(30)] },
{ "$eq": ["$$this.v", "Present"] }
]
}
}
}
}
} }
]).exec().
.then(results => {
console.log(results);
// results will be an array of employee documents with an extra field numberofPresentAttendances
})
.catch(console.error)
要获取所有员工的人数,则需要将所有文档分组为
Employee.aggregate([
{ "$group": {
"_id": null,
"totalPresent": {
"$sum": {
"$size": {
"$filter": {
"input": { "$objectToArray": "$attendances" },
"cond": {
"$and": [
{ "$in": ["$$this.k", listDatesForThePastDays(30)] },
{ "$eq": ["$$this.v", "Present"] }
]
}
}
}
}
}
} }
]).exec()
.then(results => {
console.log(results);
// results will be an array of employee documents with an extra field numberofPresentAttendances
})
.catch(console.error)