2017-01-09 10 views
4

Я пытаюсь иметь дело с временными рядами с использованием MongoDB. Общим решением, принятым сообществом, является использование поддокументов для хранения информации на разных уровнях детализации (см. Schema Design for Time Series Data in MongoDB).Обновление коллекции MongoDB: инициализировать документ со значениями по умолчанию

Например, посмотрите на следующий документ:

{ 
    timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), 
    type: “memory_used”, 
    values: [ 
    999999, // 1 second 
    … 
    1000000, // nth second 
    1500000, // n+1th second 
    … 
    2000000 // 60th 
    ] 
} 

Документ индексируется минуты информации и содержит поддокумент, которые хранят более подробную информацию на каждую секунду.

Пока все хорошо. Такой подход требует оптимизации для правильной работы:

Another optimization [..] is preallocating all documents for the upcoming time period; This never causes an existing document to grow or be moved on disk.

Для реализации вышеописанной оптимизации можно использовать $setOnInsert свойства по методу update.

db.getCollection('aCollection').update(
    { 
     timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), 
     type: “memory_used” 
    }, 
    { 
     $setOnInsert: { values: {'0': 0, '1': 0, '2': 0}}, 
     $inc: {"values.30": 1} 
    }, 
    { upsert: true } 
) 

Проблема в том, что невозможно использовать одно и то же поле в одном и том же обновлении в двух разных режимах. Выше обновление istruction генерирует следующее сообщение об ошибке:

Cannot update 'values' and 'values.30' at the same time 

Эта проблема отслеживается на этом issue.

Мой вопрос: есть ли временное решение? I префикс, что я не могу использовать любую партию, которая предварительно выделяет пустые документы, потому что я не могу знать значение проиндексированных полого априори (в приведенном выше примере, значение поля type.

Благодарности заранее.

ответ

4

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

Помните, что MongoDB гарантирует атомарность операций на одном документе. с этим фактом в виду, что мы можем работать следующим образом:

  1. Попытайтесь обновить документ, увеличивая правильность счетчиков в заданный временной отрезок. Не делайте никаких действий, просто старомодная операция обновления. Помните, что выполнение оператора обновления возвращает количество написанных документов. Если количество написанных документов больше нуля, все готово.
  2. Если количество документов, написанных обновлением, равно нулю, это означает, что относительный документ для обновления еще не присутствует в коллекции. Попробуйте вставить весь документ для указанных тегов. Поместите все счетчики (значения полей) в ноль. Также выполнение инструкции insert возвращает количество написанных документов. Если он возвращает ноль или выбрасывает исключение, неважно: это означает, что какой-то другой процесс уже вставлял документ для тех же тегов.
  3. Повторите те же вышеперечисленные обновления.

Код должен выглядеть примерно так, как показано в следующем фрагменте кода.

// Firt of all, try the update 
var result = db.test.update(
    {timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), type: “memory_used”}, 
    {$inc: {"values.39": 1}}, 
    {upsert: false} 
); 
// If the update do not succeed, then try to insert the document 
if (result.nModified === 0) { 
    try { 
    db.test.insert(/* Put here the whole document */); 
    } catch (err) { 
    console.log(err); 
    } 
    // Here we are sure that the document exists. 
    // Retry to execute the update statement 
    db.test.update(/* Same update as above */); 
} 

выше процедура работает, если предварительное условие имеет место: _id значение должно быть выведено из других полей в документе. В нашем примере значение _id будет '2013-10-10T23:06:00.000Z-memory_used. Только используя этот метод, вставка в точке 2. будет нормально терпеть неудачу.

+1

Зачем нужна вставка? У вас есть уникальный индекс по типу и метке времени? –

+0

Вы правы, мне не хватает вставить эту точку. '_id' должен быть получен из других полей в документе, например, присоединяя их к символу' -'. –