MongoDB: конвертировать день месяца месяца в метку времени в $ project [duplicate]

Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.

Здесь есть много информативных ответов с большими подробностями, я не буду повторять ни одного из них. Ключ к программированию в JavaScript имеет сначала правильную ментальную модель общего исполнения.

  1. Ваша точка входа (ов) выполняется в результате события. Например, в браузер загружается тег сценария с кодом. (Соответственно, поэтому вам, возможно, придется заботиться о готовности страницы запускать ваш код, если он требует, чтобы элементы dom были сконструированы первыми и т. Д.)
  2. Ваш код выполняется до завершения, однако многие асинхронные вызовы, которые он делает, без выполнения каких-либо ваших обратных вызовов, включая запросы XHR, установку тайм-аутов, обработчиков событий dom и т. д. Каждый из этих обратных вызовов, ожидающих выполнения, будет находиться в очереди, ожидая, что их очередь будет запущена после других событий
  3. Каждый отдельный обратный вызов XHR-запроса, установленного таймаута или dom события после вызова будет завершен.

Хорошие новости заключается в том, что, если вы хорошо понимаете этот момент, вам никогда не придется беспокоиться о гоночных условиях. Прежде всего вы должны понимать, как вы хотите упорядочить свой код как по существу ответ на разные дискретные события, и как вы хотите объединить их в логическую последовательность. Вы можете использовать обещания или новые асинхронные / ожидающие более высокие уровни в качестве инструментов для этой цели, или вы можете откатывать свои собственные.

Но вы не должны использовать какие-либо тактические инструменты для решения проблемы, пока вам не понравится актуальная проблемная область. Нарисуйте карту этих зависимостей, чтобы знать, что нужно запускать, когда. Попытка ad-hoc подхода ко всем этим обратным вызовам просто не поможет вам.

26
задан Neil Lunn 8 November 2014 в 07:31
поделиться

4 ответа

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

Единственное, что я хочу добавить здесь, это то, что вы также можете вернуть объект Date из структуры агрегации таким подходом, в отличие от «числовой» метки времени. Это лишь небольшая дополнительная математика на тех же принципах, используя $add :

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$add": [
                { "$subtract": [
                    { "$subtract": [ "$current_date", new Date(0) ] },
                    { "$mod": [ 
                        { "$subtract": [ "$current_date", new Date(0) ] },
                        1000 * 60 * 15
                    ]}
                ] },
                new Date(0)
            ]
        },
        "count": { "$sum": 1 }
    }}
])

Контексты Date(0) в JavaScript здесь представляют ту же самую «эпоху» в более короткая форма, так как 0 миллисекунд от эпохи - эпоха. Но главное, что когда «добавление» к другому объекту даты BSON выполняется с числовым идентификатором, тогда обратное к описанному условию истинно, и конечный результат на самом деле теперь является Date.

Все драйверы вернут родной тип Date на свой язык с помощью этого подхода.

14
ответ дан Blakes Seven 26 August 2018 в 00:35
поделиться

Существует несколько способов сделать это.

Первый из них - Операторы агрегирования даты , которые позволяют вам анализировать значения «даты» в документах. В частности, для «группировки» в качестве основного намерения:

db.collection.aggregate([
  { "$group": {
    "_id": {
      "year": { "$year": "$created_at" },
      "dayOfYear": { "$dayOfYear": "$created_at" },
      "hour": { "$hour": "$created_at" },
      "interval": {
        "$subtract": [ 
          { "$minute": "$created_at" },
          { "$mod": [{ "$minute": "$created_at"}, 15] }
        ]
      }
    }},
    "count": { "$sum": 1 }
  }}
])

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

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$subtract": [
                { "$subtract": [ "$created_at", new Date("1970-01-01") ] },
                { "$mod": [ 
                    { "$subtract": [ "$created_at", new Date("1970-01-01") ] },
                    1000 * 60 * 15
                ]}
            ]
        },
        "count": { "$sum": 1 }
    }}
])

. Это зависит от того, какой формат вывода вы хотите для интервала группировки. Оба они в основном представляют одно и то же и имеют достаточные данные для повторной конструкции в качестве объекта «даты» в вашем коде.

Вы можете поместить все что угодно в разделе «оператор группировки» после группировки _id. Я просто использую основной пример «подсчета» вместо любого реального заявления от себя относительно того, что вы действительно хотите сделать.


MongoDB 4.x и Upwards

Были некоторые дополнения к операторам агрегирования даты с момента написания оригинала, но из MongoDB 4.0 будет фактическое «реальное литье типов» в отличие от основных математических приемов, сделанных здесь с преобразованием даты BSON.

Для Например, мы можем использовать $toLong и $toDate в качестве новых помощников:

db.collection.aggregate([
  { "$group": {
    "_id": {
      "$toDate": {
        "$subtract": [
          { "$toLong": "$created_at" },
          { "$mod": [ { "$toLong": "$created_at" }, 1000 * 60 * 15 ] }
        ]
      }
    },
    "count": { "$sum": 1 }
  }}
])

Это немного короче и не требует определения внешняя BSON Дата для значения «epoch» как константа при определении конвейера, поэтому она вполне согласуется для всех языковых реализаций.

Это всего лишь два из «вспомогательных» методов преобразования типов, которые все привязываются к метод $convert , который является «более длинной» формой реализации, позволяющей выполнять пользовательскую обработку на null или ошибку в преобразовании.

Это возможно даже при таком литье получить информацию о Date из ObjectId первичного ключа, так как это было бы надежным источником даты создания:

db.collection.aggregate([
  { "$group": {
    "_id": {
      "$toDate": {
        "$subtract": [
          { "$toLong": { "$toDate": "$_id" }  },
          { "$mod": [ { "$toLong": { "$toDate": "_id" } }, 1000 * 60 * 15 ] }
        ]
      }
    },
    "count": { "$sum": 1 }
  }}
])

Таким образом, «типы литья» с таким преобразованием могут быть довольно мощным инструментом.

79
ответ дан Neil Lunn 26 August 2018 в 00:35
поделиться

Еще один полезный способ:

db.collection.aggregate([
  {$group: {
    _id: { 
      overallTime: { 
        $dateToString: { format: "%Y-%m-%dT%H", date: "$created_at" } 
      },
      interval: { $trunc: { $divide: [{ $minute: "$created_at" }, 15 ]}}
    },
  }},
])

И проще в секундах min , hour , day :

var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day

db.collection.aggregate([
  {$group: {
    _id: { $dateToString: { format: format, date: "$created_at" } },
  }},
])
3
ответ дан Sergey Reutskiy 26 August 2018 в 00:35
поделиться

Немного красивее для mongodb.version () 3.0

db.collection.aggregate([
    {$match: {created_at:{$exists:1}}},
    {$group: {
        _id: {$add:[
            {$dayOfYear: "$created_at" },
            {$multiply: [{$year: "$created_at"}, 1000]}
        ]},
        count: {$sum: 1 }
    }},
    {$sort:{_id:-1}}
])
7
ответ дан Stierlitz 26 August 2018 в 00:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: