Объедините конвейеры агрегации с операторами обновления - PullRequest
1 голос
/ 03 августа 2020

Я хотел бы объединить разные measurements в один документ, действующий как корзина. Я получаю отдельные измерения в этом формате:

[
  {
    "datetime": "2020-08-03T08:00:01.648475Z",
    "celsius": 20.7,
    "humidity": 57
  },
  {
    "datetime": "2020-08-03T08:05:07.756834Z",
    "celsius": 18.9,
    "humidity": 58
  }
]

Агрегированная корзина должна выглядеть так:

{
  "_id": "2020-08-03",
  "celsiusHigh": 20.7,
  "celsiusLow": 18.9,
  "firstMeasurementAt": "2020-08-03T08:00:01.648475Z",
  "lastMeasurementAt": "2020-08-03T08:05:07.756834Z",
  "humidityHigh": 58,
  "humidityLow": 57,
  "measurements": [
    {
      "datetime": "2020-08-03T08:00:01.648475Z",
      "celsius": 20.7,
      "humidity": 57
    },
    {
      "datetime": "2020-08-03T08:05:07.756834Z",
      "celsius": 18.9,
      "humidity": 58
    }
  ]
}

Начиная с MongoDB 4.2, я могу использовать Конвейеры агрегирования . Однако эти конвейеры поддерживают только стадии $addFields, $set, $project, $unset, $replaceRoot и $replaceWith. Я хотел бы использовать другие операторы обновления, такие как $setOnInsert (для установки полей только один раз - при вставке), $currentDate (для установки, например, lastUpdatedAt) или $addToSet для установки некоторых полей корзины. Без $addToSet операция выглядит довольно многословно:

{ $set : { "measurements": { $setUnion : [ { $ifNull: [ "$measurements", [] ] } , [ { "datetime": "2020-08-03T08:05:07.756834Z", "celsius": 18.9, "humidity": 58 } ] ] } } }

Есть ли возможность комбинировать конвейеры агрегации с операторами обновления?

1 Ответ

1 голос
/ 03 августа 2020

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

Но вы можете создать конвейер агрегации, использующий $ out

db.collection.aggregate([
    {
        $group: {
            _id: {$ArrayElemAt: [{$split: ["$datetime", "T"]}, 0]},
            celsiusHigh: {$max: "$celsius"},
            celsiusLow: {$min: "$celsius"},
            firstMeasurementAt: {$min: "$datetime"},
            lastMeasurementAt: {$max: "$datetime"},
            humidityHigh: {$max: "$humidity"},
            humidityLow: {$min: "$humidity"},
            measurements: {$push: "$$ROOT"}
        }
    },
    {
        $out: "collection_name"
    }
]);

Обратите внимание, что предполагается, что все datetimes сохраняются в одном формате / часовом поясе. без этого это невозможно.

...