MongoDB - обновить одно поле или другое - PullRequest
1 голос
/ 02 мая 2020

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

У меня есть следующая запись в коллекции:

{
  modelId: "5e68c7eaa0887971ea6ef54c",
  versionId: 999,
  timeStamp: "1/1/2020",
  oldValue: 'Blue',
  newValue: 'Red'
}

Я пытаюсь выполнить следующие условия с помощью одного оператора upsert, чтобы избежать многократных поездок в БД (на основании запроса, что найден документ, соответствующий modelId и versionId:

  1. Если timeStamp новой записи предшествует (lt) существующему документу, то обновляется oldValue
  2. Если timeStamp новой записи идет после (gt) существующего документа затем обновите newValue
  3. Если соответствующие записи не найдены, вставьте новую запись.

В терминах кода psuedo я пытаюсь сделать это с помощью оператора upsert:

existingRecord = item in collection matching modelId and versionId

if(existingRecord = null)
{
   //insert newRecord
}
if(newRecord.timeStamp < existingRecord.timeStamp)
{
   existingRecord.oldValue = newRecord.oldValue
   existingRecord.timeStamp = newRecord.timeStamp
}
else if(newRecord.timeStamp > existingRecord.timeStamp)
{
   existingRecord.newValue = newRecord.newValue
   existingRecord.timeStamp = newRecord.timeStamp
}

Я видел возможность сделать upsert на основе даты, что-то вроде:

db.collection.update( { id:o.id, date: { $lt:o.date } }, {$set : { o }}, {upsert:true} );

Я не знаю, как расширить это до иметь возможность обновлять oldValue или newValue на основе значения timeStamp.

Я планирую добавлять в коллекцию большое количество записей каждый день, по оценкам около 1 мм, я бы не хотел делать find(), а затем update() для каждой записи.

Я использую Пн go 4.0 и буду признателен за любые советы.

Спасибо!

1 Ответ

0 голосов
/ 02 мая 2020

Ну, в версии 4.0 вам не разрешено использовать условия в запросе на обновление. Следовательно, вместо этого вы запускаете два запроса.

db.collection.update({condition}, { $set: { o } }, { multi: true ,upsert:true });
db.collection.update({!condition}, { $set: { n } }, { multi: true ,upsert:true });

Однако в версии 4.2 добавлен db.collection.update конвейер, в котором агрегация разрешена.

И он содержит только следующие этапы агрегирования:

$addFields and its alias $set
$project and its alias $unset
$replaceRoot and its alias $replaceWith.

Надеюсь, это поможет:)

Обновление

Я добавил этап $set для обновления документа. Он обновит условие timestamp, если оно не выполнено. и применяется то же самое для других условий.

Я использовал длинное значение метки времени, которое вы можете использовать в соответствии с вашим случаем.

db.collection.update(
  {
    modelId: "5e68c7eaa0887971ea6ef54c",
    versionId: 999,
  },
  [
    {
      $set:{
        "oldValue":{
          $cond:[
            {
              $lt:[
                "timestamp",
                1598598257000
              ]
            },
            "green",
            "$oldValue"
          ]
        }
      }
    },
    {
      $set:{
        "newValue":{
          $cond:[
            {
              $gt:[
                "timestamp",
                1518598257000
              ]
            },
            "pink",
            "$newValue"
          ]
        }
      }
    }
  ]
)
...