我有以下带有出勤字段的课程模式,该字段存储具有以下键值结构的字典(字符串:列表)。特别是,出勤对象的密钥存储课程的日期,而值存储出席的学生列表(学生ID)。
var CourseSchema = new Schema({
attendance: {},
});
例如,单个课程项目可以如下:
{"_id":"559a7353186a384b54f9aea9","attendance":{"2015-12-17":["558febdb949eff4711e621e9","559020fe79f141941ddd3246"],"2015-11-14":["558febdb949eff4711e621e9","559020fe79f141941ddd3246"]}
我正在尝试返回有学生参加的课程(所以基本上返回在其出勤领域中包含特定学生ID的任何课程。我正在尝试按照以下方式进行,但它返回空的结果。是我的查询有问题吗?
我尝试检查此链接,但它对我也不起作用。 MongoDB query inside a nested array
Course.find({"attendance.$": {$in: ["558febdb949eff4711e621e9"]}}...)
答案 0 :(得分:1)
解决方案是合理的,但您的架构在此处有问题。使用"命名键"存在很大问题。使用这样的数据库,您应该将它们视为"属性"代替。
如:
{
"_id" : ObjectId("559a7353186a384b54f9aea9"),
"attendance" : [
{
"date" : ISODate("2015-12-17T00:00:00Z"),
"student" : ObjectId("558febdb949eff4711e621e9")
},
{
"date" : ISODate("2015-12-17T00:00:00Z"),
"student" : ObjectId("559020fe79f141941ddd3246")
},
{
"date" : ISODate("2015-11-14T00:00:00Z"),
"student" : ObjectId("558febdb949eff4711e621e9")
},
{
"date" : ISODate("2015-11-14T00:00:00Z"),
"student" : ObjectId("559020fe79f141941ddd3246")
}
]
}
将在架构中定义为:
AttendanceSchmema = new Schema({
"date": Date,
"student": { "type": Schema.Types.ObjectId, "ref": "Student" }
},{ "_id": false });
CourseSchema = new Schema({
"attendance": [AttendanceSchema]
});
然后我可以简单地匹配给定的学生:
Course.find(
{ "attendance.student": "559020fe79f141941ddd3246" },
{ "attendance.$": 1 }
)
甚至是特定日期的学生:
Course.find(
{ "attendance": {
"$elemMatch": {
"student": "559020fe79f141941ddd3246",
"date": { "$gte": new Date("2015-12-15"), "$lt": new Date("2015-12-16") }
}
}},
{ "attendance.$": 1 }
)
两者之间的可能性更大。我们将所有这些放在一个带有"属性"的单个数组中的原因就像属性一样,它使查询和存储变得简单。
如果没有这样的改变,你就会遇到可怕的执行查询,例如:
Course.find({ "$where": function() {
return Object.keys(this.attendance).some(function(k) {
return this.attendance[k].indexOf("558febdb949eff4711e621e9")
});
}})
当然假设这些值目前是"字符串",因为它们似乎是Mixed
类型。
甚至更糟糕的查询更复杂的东西,也无法告诉你哪个位置匹配。但到目前为止,最糟糕的是这些不可能使用"指数"为了匹配。
因此,您真的应该考虑将数据库架构更改为一个支持以最有效的方式查询的表单。