【问题标题】:MongoDB query: how to find if a string within a nested objectsMongoDB查询:如何查找嵌套对象中的字符串
【发布时间】:2017-11-16 14:39:49
【问题描述】:

我有以下带有出勤字段的课程架构,它存储具有以下键值结构(字符串:列表)的字典。特别是,出勤对象的键存储上课日期,而值存储出席的学生列表(学生 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"]}}...)

【问题讨论】:

  • 这里的问题是你有像"2015-12-17" 这样的“命名键”,这会妨碍引用的解决方案有用。因此,您的模式设计选择是错误的。如果您更改架构,那么您可以以有效的方式完全按照您的意愿行事。目前,唯一的方法根本不是很有效。

标签: javascript mongodb mongoose


【解决方案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 类型。

更糟糕的查询更复杂,也无法告诉您匹配哪个位置。但到目前为止,最糟糕的是这些不可能使用“索引”来匹配。

因此,您确实应该考虑将此处的数据库架构更改为能够以最有效的方式支持查询的表单。

【讨论】:

  • 非常感谢,我会调查的!中途更改数据库模式是否被认为是不好的形式?
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-21
  • 2020-02-26
  • 1970-01-01
相关资源
最近更新 更多