Здесь важно учесть, что на самом деле нужно , чтобы продолжать использовать "операторы регулярных запросов" здесь, иначе вы резко снизите производительность. Идея состоит в том, чтобы всегда писать запрос, который может фактически «использовать индекс», а затем убедиться, что у вас есть индекс.
Таким образом, выбор «дней» является стандартным запросом диапазона, а остаток возвращается к фильтрации выражений с «вычислениями» с учетом «уже выбранных» документов с помощью правильно с указанием стандартного запроса условия сначала :
MongoDB 3.6 - $ expr
db.collection.find({
"date": { "$gte": new Date("2017-05-01"), "$lt": new Date("2018-03-16") },
"$expr": {
"$and": [
{ "$gte": [{ "$hour": "$date" }, 15 ] },
{ "$lt": [{ "$hour": "$date", 17 ] }
]
}
})
Использует оператор запроса $expr
для оценки структуры агрегирования логические операторы и операторы даты . Операторы регулярного сравнения для выражения диапазона дат.
Более низкие версии - Aggregate и $ redact
db.collection.aggregate([
{ "$match": {
"date": { "$gte": new Date("2017-05-01"), "$lt": new Date("2018-03-16") }
}},
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$gte": [{ "$hour": "$date" }, 15 ] },
{ "$lt": [{ "$hour": "$date", 17 ] }
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Те же выражения агрегации, но применяемые с использованием стадии конвейера $redact
. То же самое Операторы регулярного сравнения для выражения диапазона дат в пределах $match
.
Все версии - $ где
var startHour = 15,
endHour = 17;
db.collection.find({
"date": { "$gte": new Date("2017-05-01"), "$lte": new Date("2018-03-15") },
"$where": `this.data.getUTCHours() => ${startHour}
&& this.data.getUTCHours() < ${endHour}`
})
Использование оценки JavaScript с $where
. Доступно во всех версиях, если только сценарии на стороне сервера не были явно отключены. Обратите внимание, что для основного выбора диапазона дат используются «одинаковые» и операторы регулярного сравнения .
В ALL случаях обязательно выражать условие "стандартный оператор запроса" "first" . Без этого MongoDB не может использовать индекс, если он присутствует в данных, и должен будет сканировать каждый документ в коллекции, чтобы вычислить условия и посмотреть, возвращать ли документ или нет.
Добавление условия «стандартный оператор» с диапазонами $gte
и $lt
позволяет использовать индекс, а оставшееся «вычисленное» логическое выражение является только фактически применяется к тем документам, которые уже соответствуют «первому» условию.
Для «бонуса» вы можете даже ограничить время самими «днями», так что вы даже не учитываете время до 15:00 или после 17:00 в начальный и конечный дни соответственно:
"date": { "$gte": new Date("2017-05-01T15:00"), "$lt": new Date("2018-03-16T17:00") }
Поэтому, где это возможно, всегда "используйте индекс" и убедитесь, что ваши выражения запроса действительно созданы для их использования, в отличие от других форм, которые не используются.
ПРИМЕЧАНИЕ Общая логика здесь заключается в том, что «производительность» всех представленных здесь решений должна масштабироваться в порядке представления, с $expr
от лучшего до $where
наихудшего. Однако в настоящее время, по-видимому, в выпуске MongoDB 3.6 наблюдается регрессия, где на самом деле $where
обычно работает лучше, чем его аналоги, использующие собственные операторы.
Однако это не должно быть «текущим» случаем и должно быть решено, поэтому обычно рекомендуется использовать составы собственных операторов, а не логику JavaScript с $where
.