Как отфильтровать по дате и времени независимо в Монго? - PullRequest
0 голосов
/ 01 мая 2018

Как отфильтровать по дате и времени независимо в Монго?

Я хочу иметь возможность сохранять и дату, и дату независимо в базе данных, где я мог бы фильтровать по дате и времени независимо.

Должен ли я иметь только одно поле, которое сохраняет объект даты? Если да, то как я могу фильтровать по времени. Как я могу получить статистику о записях, например, с датой с 01/05/2017 по 15/03/2018 И записи должны иметь время, которое находится между 15:00 и 17:00 (так что запись, которая имеет дату 12/03/2018 и время 17:05 не должно включаться).

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Здесь важно учесть, что на самом деле нужно , чтобы продолжать использовать "операторы регулярных запросов" здесь, иначе вы резко снизите производительность. Идея состоит в том, чтобы всегда писать запрос, который может фактически «использовать индекс», а затем убедиться, что у вас есть индекс.

Таким образом, выбор «дней» является стандартным запросом диапазона, а остаток возвращается к фильтрации выражений с «вычислениями» с учетом «уже выбранных» документов с помощью правильно с указанием стандартного запроса условия сначала :

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.

0 голосов
/ 01 мая 2018

Наличие документов, как показано ниже:

db.col.save({ date: new Date("2018-03-02T16:00:00Z") }); // matches
db.col.save({ date: new Date("2018-03-16T16:00:00Z") }); // doesn't match
db.col.save({ date: new Date("2017-05-02T19:00:00Z") }); // doesn't match
db.col.save({ date: new Date("2017-06-15T15:00:00Z") }); // matches

Вы можете использовать $ redact , чтобы указать условие в качестве выражения. Чтобы извлечь час из Date, вы можете использовать оператор $ hour :

db.col.aggregate([
    {
        $redact: {
            $cond: {
                if: { $and: [
                        { $gte: [ "$date", new Date("2017-05-01T00:00:00Z") ] },
                        { $lt: [ "$date", new Date("2018-03-16T00:00:00Z") ] },
                        { $gte: [ { $hour: "$date" }, 15 ] },
                        { $lt: [ { $hour: "$date" }, 17 ] }
                    ] 
                },
                then: "$$KEEP",
                else: "$$PRUNE"            
            }
        } 
    }
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...