Запрос MongoDB: как найти строку внутри вложенных объектов

1

У меня есть следующая схема курса с полем посещаемости, в котором хранится словарь со следующей структурой ключевого значения (строка: список). В частности, ключ объекта посещаемости хранит дату класса, а значение хранит список участвующих студентов (идентификаторы студентов).

var CourseSchema = new Schema({
  attendance: {},
});

Например, один пункт курса может быть следующим:

{"_id":"559a7353186a384b54f9aea9","attendance":{"2015-12-17":["558febdb949eff4711e621e9","559020fe79f141941ddd3246"],"2015-11-14":["558febdb949eff4711e621e9","559020fe79f141941ddd3246"]}

Я пытаюсь вернуть курсы, в которых участвовал учащийся (так что в принципе возвратите любой курс, который в поле его посещаемости содержит конкретный идентификатор ученика. Я пытаюсь сделать это следующим образом, но он возвращает пустые результаты. с моим запросом?

Я попытался проверить эту ссылку, но это не работает для меня. Запрос MongoDB внутри вложенного массива

Course.find({"attendance.$": {$in: ["558febdb949eff4711e621e9"]}}...)
Теги:
mongoose

1 ответ

1
Лучший ответ

Решение звучит, но ваша схема здесь виновата. Существуют большие проблемы с использованием "named keys" с такой базой данных, и вы должны рассматривать их как "атрибуты".

Например, в:

{
    "_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 типу.

И еще худшие запросы для чего-то более сложного, что также не может сказать вам, какая позиция была сопоставлена. Но, самое главное, они не могут использовать "индекс", чтобы соответствовать.

Поэтому вам действительно стоит подумать об изменении схемы базы данных здесь в форме, которая будет поддерживать запрос наиболее эффективным способом.

  • 0
    Большое спасибо, и я посмотрю на это! Считается ли плохой формой просто менять схемы базы данных на полпути?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню