在更改NDB字段的属性类型时迁移数据 [英] Migrating data when changing an NDB field's property type

查看:114
本文介绍了在更改NDB字段的属性类型时迁移数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我最初创建了一个ndb.Model,并且想要将一个字段的ndb属性类型(例如IntegerProperty改为StringProperty),但是想要转换存储在该字段中的当前数据,以便我不会丢失该数据。一种方法是简单地创建一个新的字段名称,然后用脚本迁移数据,但是还有其他更方便的方法来完成这个吗?



例如,假设我有以下模型:

  class Car(ndb.Model):
name = ndb.StringProperty()
production_year = ndb.IntegerProperty()

我存储了实体的一个实例:

  c =新车()
c.name =保时捷
c.production_year = 2013

并且希望将production_year更改为ndb.StringProperty(),而不会丢失我设置的值仍然存在,但不可检索)。如果我只是将production_year更改为ndb.StringProperty()的实例,则字段值不会报告有意义的值,因为该类型不匹配。



所以如果我将模型更改为:

  class Car(ndb.Model):
name = ndb.StringProperty()
production_year = ndb.StringProperty()

尝试使用点符号检索字段会导致值为None。任何人都会遇到这种情况,你能解释你做了什么来解决它吗?感谢。

解决方案

您如何解决这个问题将取决于您拥有多少个实体。
如果实体的数量相对较少,我会使用remote_api并从数据存储中检索原始基础数据,然后直接操作数据,然后将其写回,而不是使用模型。例如,这将获取原始实体,并且可以像字典一样访问属性。此代码几乎从较低级别的appengine SDK代码
中提取。

  from google.appengine.api import data store 
from google.appengine.api import datastore_errors
$ b $ def get_entities(keys):
rpc = datastore.GetRpcFromKwargs({})
keys,multiple = datastore.NormalizeAndTypeCheckKeys (键)
实体=无
尝试:
实体= datastore.Get(键,rpc = rpc)
除了datastore_errors.EntityNotFoundError:
断言不是

返回实体

def put_entities(实体):
rpc = datastore.GetRpcFromKwargs({})
keys = datastore.Put(entities,rpc = rpc )
返回键

你可以这样使用它(我使用fetch来简化事物这个例子中的代码明智)

$ $ $ $ $ $ $ $ $ b results = get_entities([i.to_old_key()for i in x])

for i in re
i ['production_year'] = unicode(i ['production_year'])

put_entities(results)

这是我有的旧代码,并且 datastore.NormalizeAndTypeCheckKeys 采用旧的数据库样式键,我没有看过对于ndb风格的键有一个等效的函数,但这确实有效。 (刚刚测试过; - )

这种方法可以在不部署任何新代码的情况下迁移数据。

如果您拥有数百万个实体,那么您应该看看其他处理方法,即使用此代码并使用mapreduce。

Suppose I initially create an ndb.Model and wanted to change a field's ndb property type (e.g. IntegerProperty to StringProperty), but wanted to cast the current data stored in that field so that I don't lose that data. One method would be to simply create a new field name and then migrate the data over with a script, but are there other more convenient ways of accomplishing this?

For example, suppose I had the following model:

class Car(ndb.Model):
    name = ndb.StringProperty()
    production_year = ndb.IntegerProperty()

And I stored an instance of the entity:

c = new Car()
c.name = "Porsche"
c.production_year = 2013 

And wanted to change production_year to an ndb.StringProperty() without "losing" the value I set (it would still exist, but would not be retrievable). If I just change production_year to an instance of ndb.StringProperty(), the field value does not report a value which makes sense since the type doesn't match.

So if I changed the model to:

class Car(ndb.Model):
    name = ndb.StringProperty()
    production_year = ndb.StringProperty()

Attempting to retrieve the field with dot notation would result in a value of None. Anyone run into this situation, and could you explain what you did to solve it? Thanks.

解决方案

How you approach this will depend on how many entities you have. If you a relatively small number of entities say in the 10000's I would just use the remote_api and retrieve the raw underlying data from the datastore and manipulate the data directly then write it back, not using the models. For instance this will fetch raw entities as and properties can be accessed like a dictionary. This code is pretty much lifted from the lower level appengine SDK code .

from google.appengine.api import datastore
from google.appengine.api import datastore_errors

def get_entities(keys):
    rpc = datastore.GetRpcFromKwargs({})
    keys, multiple = datastore.NormalizeAndTypeCheckKeys(keys)
    entities = None
    try:
        entities = datastore.Get(keys, rpc=rpc)
    except datastore_errors.EntityNotFoundError:
        assert not multiple

    return entities

def put_entities(entities):
    rpc = datastore.GetRpcFromKwargs({})
    keys = datastore.Put(entities, rpc=rpc)
    return keys

You would use this as follows (I am using fetch to simplify things a bit code wise for this example)

x = Car.query(keys_only=True).fetch(100)
results = get_entities([i.to_old_key() for i in x])

for i in results:
    i['production_year'] = unicode(i['production_year'])

put_entities(results)

This is old code I have and datastore.NormalizeAndTypeCheckKeys takes the old db style key, I haven't looked to see of there is an equivalent function for ndb style keys, but this does work. (Just tested it ;-)

This approach allows you to migrate data without deploying any new code.
If you have millions of entities then you should look at other approaches for processing, ie using this code and using mapreduce.

这篇关于在更改NDB字段的属性类型时迁移数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆