2012-02-22 4 views
1

Как запустить миграцию, чтобы изменить тип поля в Mongoid/MongoDB без потери данных?Изменить тип поля в Mongoid без потери данных

В моем случае я пытаюсь преобразовать из BigDecimal (хранящегося в виде строки) в Integer, чтобы хранить деньги. Мне нужно преобразовать строковое десятичное представление в центы для целого числа. Я не хочу потерять существующие данные.

Я предполагаю, что шаги, может быть что-то вроде:

  1. создать новое поле типа Integer с новым именем, скажем amount2
  2. развертывания производства и запустить миграцию (или задачу рейка), который преобразует каждый amount к правильному значению для amount2
  3. (все это время существующего код все еще использует amount и нет времени простоя с точки зрения пользователей)
  4. взять сайт вниз для технического обслуживания, бегите го е миграции еще раз, чтобы захватить любые amount поля, которые могли бы изменились за последние несколько минут
  5. удалить amount и переименовать amount2 в amount
  6. развернуть новый код, который ожидает amount быть целым
  7. принести сайт обратно

похоже Mongoid предлагает rename метод: http://mongoid.org/docs/persistence/atomic.html#rename

Но я немного запутался как это используется. Если у вас есть поле с именем amount2 (и вы уже удалили amount), вы просто запустили Transaction.rename :amount2, :amount? Тогда я предполагаю, что это немедленно нарушает базовое представление, поэтому после этого вы должны перезапустить сервер приложений. Что произойдет, если вы запустите это, пока amount все еще существует? Переписывается ли он, не работает или пытается преобразовать его самостоятельно?

Спасибо!

+0

. Звук похоже. Но я не уверен, нужен ли вам перезапуск или нет. Во-первых, вам нужно будет обновить имя поля в модели правильно? Что касается перезаписи, я не уверен, но это часть этой ссылки http://whyjava.wordpress.com/2012/02/07/how-to-rename-field-in-all-the-mongodb -documents /, похоже, предполагает, что он попытается написать и, возможно, переписать поле, если оно существует. Таким образом, это не похоже на регулярное переименование на основе SQL, а перемещение каждого значения документа по отдельности. Имеет смысл? –

+0

Хм ... не уверен, хотел бы получить рабочий пример от начала до конца. Я отправлю его, если он пройдет успешно. –

ответ

3

Хорошо, я справился. Я думаю, что есть более быстрый способ с помощью консоли Монго с чем-то вроде этого: MongoDB: How to change the type of a field?

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

  • создать новое поле типа Integer с новым именем, скажем amount2
  • преобразовать каждый amount в нужное значение для amount2 в консоли или граблями задачи

Mongoid.identity_map_enabled = false 
Transaction.all.each_with_index do |t,i| 
    puts i if i%1000==0 
    t.amount2 = t.amount.to_money 
    break if !t.save 
end 

Обратите внимание, что .all.each работает отлично (вам не нужно использовать .find_each или .find_in_batches, как обычные activerecord с mysql) из-за курсоров mongodb. Он не будет заполнять память, пока идентификатор отключен.

  • взять сайт для технического обслуживания, запустите Миграционной еще один раз, чтобы захватить какую-либо сумму полей, которые могли бы изменились за последние несколько минут (что-то вроде Transaction.where(:updated_at.gt => 1.hour.ago).each_with_index...

  • Закомментируйте field :amount, type: BigDecimal в вашей модели, вы больше не хотите, чтобы mongoid узнал об этом поле, и нажмите этот код.

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

Mongoid.identity_map_enabled = false 
Transaction.all.each_with_index do |t,i| 
    puts i if i%1000==0 
    t.rename :amount2, :amount 
end 

Это атомная и не требует сохранения на модели.

  • обновление вашей модели, чтобы отразить новый тип столбца field :amount, type: Integer
  • развернуть и вывести сайт обратно

Как уже упоминалось, я думаю, что это лучший способ, так что если у кого-то есть какие-то советы, пожалуйста, поделитесь , Благодаря!

+0

только вопрос. Любая вероятность того, что ваш курсор перегорит для больших наборов данных? –

+0

Да, я думаю, что время ожидания курсора по умолчанию монго составляет 10 минут, может случиться точно. если вы можете написать его idempotently (проверьте, является ли amount2 равным нулю) и запускайте его несколько раз, это может сработать. Определенно кажется сложнее, чем должно быть. –

+0

Обновление, возможно, я должен был использовать это: https://github.com/nviennot/mongoid_lazy_migration Выглядит легче, чем то, что я сделал –

Смежные вопросы