2013-12-16 25 views
7

Sto lavorando con mongoengine e sto provando a fare una semplice migrazione. Ho un campo che mi piacerebbe migrare da essere un campo di corda a un riferimento a un altro oggetto. Ho pianificato di eseguire la migrazione a mano, prima costruendo il nuovo oggetto in base alla stringa che proviene dal vecchio StringField e quindi impostandola esplicitamente.Migrazioni in mongoengine: InvalidId

Il problema è che non riesco nemmeno ad accedere a uno dei documenti di livello superiore più una volta ho cambiato il tipo di campo. È necessario creare un campo "fittizio" nel codice di classe del mio documento come segnaposto per il nuovo campo? Mi sembra un po 'imbarazzante quindi presumo che ci sia un modo migliore?

Ecco l'errore, poiché il campo che esce dal DB (StringField) non è coerente con un campo di riferimento.

/usr/lib/python2.7/site-packages/mongoengine/queryset/base.pyc in __getitem__(self, key) 
    149     return queryset._get_as_pymongo(queryset._cursor.next()) 
    150    return queryset._document._from_son(queryset._cursor[key], 
--> 151             _auto_dereference=self._auto_dereference) 
    152   raise AttributeError 
    153 

/usr/lib/python2.7/site-packages/mongoengine/base/document.pyc in _from_son(cls, son, _auto_dereference) 
    568     try: 
    569      data[field_name] = (value if value is None 
--> 570           else field.to_python(value)) 
    571      if field_name != field.db_field: 
    572       del data[field.db_field] 

/usr/lib/python2.7/site-packages/mongoengine/fields.pyc in to_python(self, value) 
    935   not isinstance(value, (DBRef, Document, EmbeddedDocument))): 
    936    collection = self.document_type._get_collection_name() 
--> 937    value = DBRef(collection, self.document_type.id.to_python(value)) 
    938   return value 
    939 

/usr/lib/python2.7/site-packages/mongoengine/base/fields.pyc in to_python(self, value) 
    390  def to_python(self, value): 
    391   if not isinstance(value, ObjectId): 
--> 392    value = ObjectId(value) 
    393   return value 
    394 

/usr/lib/python2.7/site-packages/bson/objectid.pyc in __init__(self, oid) 
    88    self.__generate() 
    89   else: 
---> 90    self.__validate(oid) 
    91 
    92  @classmethod 

/usr/lib/python2.7/site-packages/bson/objectid.pyc in __validate(self, oid) 
    192      raise InvalidId("%s is not a valid ObjectId" % oid) 
    193    else: 
--> 194     raise InvalidId("%s is not a valid ObjectId" % oid) 
    195   else: 
    196    raise TypeError("id must be an instance of (%s, %s, ObjectId), " 

InvalidId: Was Dirty: a2111fe89383bb562738b81c2b63fe78e877ed32 is not a valid ObjectId 

risposta

0

ho sempre migrato le cose a mano con una collezione intermedio o un campo intermedio nella stessa collezione, ma this example lo fa apparire come non avete a. L'overflow dello stack odia i collegamenti esterni, quindi includo l'esempio riportato di seguito. Fare attenzione con quella parte "drop_collection"!

import unittest 
from mongoengine import * 


class Test(unittest.TestCase): 

    def setUp(self): 
     conn = connect(db='mongoenginetest') 

    def create_old_data(self): 
     class Person(Document): 
      name = StringField() 
      age = FloatField() # Save as string 

      meta = {'allow_inheritance': True} 

     Person.drop_collection() 

     Person(name="Rozza", age=35.00).save() 

     rozza = Person._get_collection().find_one() 
     self.assertEqual(35.00, rozza['age']) 

    def test_migration(self): 

     self.create_old_data() 

     class Person(Document): 
      name = StringField() 
      age = StringField() 

      meta = {'allow_inheritance': True} 

     for p in Person.objects: 
      p.age = "%s" % p.age 
      p.save() 

     rozza = Person.objects.first() 
     self.assertEqual("35.0", rozza.age) 

if __name__ == '__main__': 
    unittest.main() 
0

Le 2 opzioni vorrei suggerire per lo script di migrazione:

  • utilizzando DynamicField sul campo è necessario migrare dovrebbe consentire di leggere objectIds e memorizzare indietro DBRefs
  • facendo la migrazione in pymongo direttamente (la collezione di pymongo è accessibile tramite Person._get_collection()) e il looping sugli articoli, aggiornando & salvando