Монго запрос, чтобы получить 1 документ в день с параметром времени - PullRequest
2 голосов
/ 24 октября 2019

У меня проблемы с получением документов нужных дат из моей БД.

Моя структура базы данных выглядит примерно так:

{
  date: 2019-10-24T10:00:00.000Z,
  value: 6
},
{
  date: 2019-10-24T10:01:03.000Z,
  value: 6
},
{
  date: 2019-10-24T10:02:35.000Z,
  value: 6
},
...

И пытаюсь получить запрос, которыйпринимает 2 параметра:

  • startDate (endDate - x дней)
  • endDate

И доставляет 1 документ в день между startDate и endDate, этот документ необходимчтобы время (ЧЧ: мм: сс) было ближе к концу endDate. Примерно так:

start = new Date('2019-10-22T10:00:00.000Z')
end = new Date('2019-10-24T10:00:00.000Z)

{
  date: '2019-10-22T09:59:13.000Z',
  value: 10
},
{
  date: '2019-10-23T10:00:00.000Z',
  value: 17
},
{
  date: '2019-10-24T09:58:55.000Z',
  value: 10
}

Прямо сейчас у меня есть эта агрегатная функция, которая получает мне первый документ каждого дня:

.aggregate([
    {
      $match: {
        date: { $gte: ISODate('2019-05-26T12:00:00.000Z'), $lte: ISODate('2019-10-26T12:00:00.000Z') }
      }
    },
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: '$date',
        day: {
          '$dayOfMonth': '$date'
        },
        month: {
          '$month': '$date'
        },
        year: {
          '$year': '$date'
        }
      }
    },
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: 1,
        date: {
          '$concat': [
            {
              $substr: ['$year', 0, 4]
            },
            '-',
            {
              $substr: ['$month', 0, 2]
            },
            '-',
            {
              $substr: ['$day', 0, 2]
            }
          ]
        }
      }
    },
    {
      $group: {
        _id: '$date',
        objId: {
          $first: '$_id'
        },
        value: {
          $first: '$value'
        },
        date: {
          $first: '$docDate'
        }
      }
    },
    {
      $project: {
        _id: '$objId',
        value: 1,
        date: 1
      }
    },
    {
      '$sort': {
        date: 1
      }
    }
  ]
)

Ответы [ 2 ]

2 голосов
/ 25 октября 2019

Так что я думаю, что этот запрос может быть тем, что вы ищете ...

db.records.aggregate([
    { $match: { 
         date: { 
           $gte: ISODate('2019-05-03T12:01:07Z'), 
           $lte: ISODate('2019-05-07T12:01:07Z') 
        }
      }
    },
    { $addFields:  {
         date_string: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }
       }
    },
    { $sort: { date: -1 } },
    { $group: {
        _id: "$date_string",
        my_doc: { $first: "$$ROOT" }
      }
    },
    { $replaceRoot: { newRoot: "$my_doc" } },
    { $project: { date_string: 0 } }, 
    { $sort: { date: 1 } }
])

Разбивка стратегии конвейера:

  1. $match - выбрать диапазон записей для рассмотрения по диапазону дат

  2. $ addFields - получить только строку даты без времени. Это необходимо для фактической группировки $ group. Если строка содержит время тоже, она не будет правильно группироваться

  3. $ sort date -1 = это необходимо до группировки, поэтому мы можем использовать оператор $ first в $ group

  4. $ group - агрегировать и использовать $ first для выбора элемента в группировке

  5. $ replaceRoot - преобразовать вывод конвейера обратно в исходный формат документа

  6. $ project - удалить временное поле date_string

  7. $ date sort 1 - вернуть данные в обычном отсортированном порядке.

Выход:

{ "_id" : ObjectId("5db21090d15e418f2d5b7b4e"), "value" : 3, "date" : ISODate("2019-05-03T12:01:07Z") }
{ "_id" : ObjectId("5db21090d15e418f2d5b7b4f"), "value" : 4, "date" : ISODate("2019-05-04T12:07:07Z") }
{ "_id" : ObjectId("5db21090d15e418f2d5b7b53"), "value" : 5, "date" : ISODate("2019-05-05T12:01:07Z") }
{ "_id" : ObjectId("5db21090d15e418f2d5b7b54"), "value" : 6, "date" : ISODate("2019-05-06T12:01:07Z") }
{ "_id" : ObjectId("5db21090d15e418f2d5b7b55"), "value" : 7, "date" : ISODate("2019-05-07T12:01:07Z") }
1 голос
/ 25 октября 2019

Я нашел решение, добавил переменную минут и сопоставил ее. Также изменил данные группы, чтобы получить $ last вместо $ first.

db.getCollection('weightedaverages').aggregate([
    {
      $match: {
        date: { $gte: ISODate('2019-05-26T15:00:00.000Z'), $lte: ISODate('2019-10-26T15:00:00.000Z') }
      }
    },
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: '$date',
        day: {
          '$dayOfMonth': '$date'
        },
        month: {
          '$month': '$date'
        },
        year: {
          '$year': '$date'
        },
        minutes: {
          $add: [
            {
              $multiply: [
                {
                  '$hour': '$date'
                },
                60
              ] 
            }, 
            {
              '$minute': '$date'
            } 
          ]
        } 
      }
    },
    { $match: { 'minutes' : { $lte : ISODate('2019-10-26T13:20:00.000Z').getHours() * 60 + ISODate('2019-10-26T13:20:00.000Z').getMinutes()}}},
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: 1,
        date: {
          '$concat': [
            {
              $substr: ['$year', 0, 4]
            },
            '-',
            {
              $substr: ['$month', 0, 2]
            },
            '-',
            {
              $substr: ['$day', 0, 2]
            }
          ]
        }
      }
    },
    {
      $group: {
        _id: '$date',
        objId: {
          $last: '$_id'
        },
        value: {
          $last: '$value'
        },
        date: {
          $last: '$docDate'
        }
      }
    },
    {
      $project: {
        _id: '$objId',
        value: 1,
        date: 1
      }
    },
    {
      '$sort': {
        date: 1
      }
    }
  ]
)

Вывод:

{
  "date" : ISODate("2019-08-20T15:00:13.633Z"),
  "value" : 10
},
{
  "date" : ISODate("2019-08-19T15:00:19.850Z"),
  "value" : 5
},
...
{
  "date" : ISODate("2019-06-20T14:59:48.000Z"),
  "value" : 7
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...