Совокупный запрос в MongoDB с использованием JavaScript, пытающегося преобразовать дату строки UTC в объект Date - PullRequest
0 голосов
/ 15 мая 2018

Я пытаюсь сгруппировать даты по часам и загружаю данные из файла json. Дата и время в формате UTC представлены в виде строк. Как мне преобразовать их в объекты Date, используя JavaScript в метеоре?

var data = Subjects.aggregate([{$match: no_null},
                  { $project: 
                    { bin: { $hour: new Date("$metrics."+metric") } 
                  } },
                  {$group: { _id: "$bin", count: {$sum: 1} } } ])

Метрика уже в формате UTC.

Вот один документ.

{
    "metrics": {
      "ACT_04": 3.733333333, 
      "ACT_05": 14.5, 
      "ACT_02": "1970-01-01T05:02:30Z", 
      "ACT_03": 7.0833333329999997, 
      "ACT_01": "1970-01-01T20:03:00Z"
    }, 
    "subject_id": "M10965219", 
    "name": "sub-M10965219_Act"
  }

1 Ответ

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

Если «строка» находится в «лексическом» формате ISO, как в "2018-05-15T20:59:31.502Z", то вы «могли бы» получить $substr частей:

Subjects.aggregate([
  { "$group": {
    "_id": { "$substr": ["$metrics."+metric,0,10] },
    "count": { "$sum": 1 }
  }}
])

Если у вас есть MongoDB 3.6, то вы «могли бы» использовать $dateFromString, чтобы фактически преобразовать это в формат даты BSON, но вы, вероятно, хотите аналогичным образом обрезать эту строку аналогичным образом для любой даты Вы действительно хотите округлить:

Subjects.aggregate([
  { "$group": {
    "_id": {
      "$dateFromString": {
        "dateString": { "$substr": ["$metrics."+metric,0,10] }
      }            
    },
    "count": { "$sum": 1 }
  }}
])

MongoDB 4.0 имеет $toDate для немного короче и делает то же самое преобразование даты BSON:

Subjects.aggregate([
  { "$group": {
    "_id": {
      "$toDate": { "$substr": ["$metrics."+metric,0,10] }
    },
    "count": { "$sum": 1 }
  }}
])

Но основной факт в том, что если ваша «строка» на самом деле не выглядит так и не может быть по-разному разбита на части строки поддерживаемыми операторами, тогда вам, как правило, гораздо лучше преобразовать даты, хранящиеся в вашем Во-первых, коллекции должны быть настоящими. Даты BSON.

Вместо этого рекомендуется «выполнить» преобразование данных. Оболочки mongo должно быть достаточно для запуска одноразовых преобразований:

var batch = [];

db.subjects.find().forEach(doc => {

  var fields = Object.keys(doc.metrics).map(k => ({
    ['metrics.'+k]: new Date(doc.metrics[k]),
  })).reduce((acc,curr) => Object.assign(acc,curr),{});

  batch.push({
    "updateOne": {
      "filter": doc._id",
      "update": { "$set": fields }
    }
  });

  if ( batch.length > 1000 ) {
     db.subjects.bulkWrite(batch);
     batch = []
  }
})

if ( batch.length > 0 ) {
  db.subjects.bulkWrite(batch);
  batch = [];
}

Это основной процесс. Конечно, если ваши «строки» не в формате ISO или не подходят для передачи в Date() для преобразования, тогда вам действительно нужно принять другие меры.

По крайней мере, дата BSON представляет собой 8-битную структуру данных с «внутренним» числовым представлением, где в качестве эквивалентной «строки» она составляет не менее 24 байтов и даже больше со словами, обозначающими дни и месяцы. При работе с базой данных имеет смысл сохранять данные, которые по существу имеют «числовой» характер, в этой форме.

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

Примечание $substr считается устаревшим и фактически теперь псевдонимы $substrBytes, или вы можете использовать $substrCP в зависимости от на фактическое кодирование данных. Более старые выпуски MongoDB до 3.2 имеют только выражение $substr.

...