MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Changer le type de champ dans Mongoid sans perdre de données

Ok j'ai réussi. Je pense qu'il existe un moyen plus rapide d'utiliser la console mongo avec quelque chose comme ceci :MongoDB :Comment changer le type d'un champ ?

Mais je n'ai pas pu faire fonctionner la conversion, j'ai donc opté pour cette méthode plus lente dans la console des rails avec plus de temps d'arrêt. Si quelqu'un a une solution plus rapide, merci de la publier.

  • créer un nouveau champ Integer avec un nouveau nom, par exemple amount2
  • convertir chaque amount à la bonne valeur pour amount2 dans une tâche console ou rake

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

Notez que .all.each fonctionne bien (vous n'avez pas besoin d'utiliser .find_each ou .find_in_batches comme activerecord normal avec mysql) à cause des curseurs mongodb. Il ne remplira pas la mémoire tant que l'identity_map est désactivé.

  • arrêtez le site pour maintenance, exécutez la migration une fois de plus pour capturer tous les champs de montant qui auraient pu changer au cours des dernières minutes (quelque chose comme Transaction.where(:updated_at.gt => 1.hour.ago).each_with_index...

  • commentez le field :amount, type: BigDecimal dans votre modèle, vous ne voulez plus que mongoid connaisse ce champ, et poussez ce code

  • exécutez maintenant un autre script pour renommer votre colonne (il écrase toutes les anciennes valeurs de chaîne BigDecimal dans le processus). Vous devrez peut-être commenter toutes les validations que vous avez sur le modèle qui attendent l'ancien champ.

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

Ceci est atomique et ne nécessite pas de sauvegarde sur le modèle.

  • mettez à jour votre modèle pour refléter le nouveau type de colonne field :amount, type: Integer
  • déployer et remettre le site en ligne

Comme mentionné, je pense qu'il existe un meilleur moyen, donc si quelqu'un a des conseils, merci de les partager. Merci !