Google cloud platform 从Google云数据存储导出将关键属性上的应用程序id设置为b~<;应用程序id>;。这使得进口商品无法使用
我想导出实时数据存储并将其导入到本地数据存储模拟器中,并对其运行测试 由于app_id在所有KeyProperties中都设置为b~,因此密钥映射被抛出 1) :Google cloud platform 从Google云数据存储导出将关键属性上的应用程序id设置为b~<;应用程序id>;。这使得进口商品无法使用,google-cloud-platform,google-cloud-firestore,google-cloud-datastore,app-engine-ndb,Google Cloud Platform,Google Cloud Firestore,Google Cloud Datastore,App Engine Ndb,我想导出实时数据存储并将其导入到本地数据存储模拟器中,并对其运行测试 由于app_id在所有KeyProperties中都设置为b~,因此密钥映射被抛出 1) :gcloud数据存储导出gs:// 2) 将导出复制到本地文件夹:gsutil-m cp-r gs:// 3) 导入到本地数据存储:curl-X POST localhost:/v1/projects/:Import-H'内容类型:application/json'-d'{“input\u url”:“/.total\u export\
gcloud数据存储导出gs://
2) 将导出复制到本地文件夹:gsutil-m cp-r gs://
3) 导入到本地数据存储:curl-X POST localhost:/v1/projects/:Import-H'内容类型:application/json'-d'{“input\u url”:“/.total\u export\u metadata”}”
4) 使用--support\u datastore\u emulator=true--应用程序启动dev\u appserver.py
上面的一切似乎都起作用了,您可以调出所有实体,但是,具有KeyProperty的实体失败了,因为键值已将应用程序设置为b~
,感谢您的报告。这是模拟器中的一个bug,我们正在修复。
字符串“b~”是云数据存储中的完整应用程序id。您应该能够通过在导入请求中添加此“b~”来获得一致的数据:
curl -X POST localhost:<emulator_port>/v1/projects/b~<app-id>:import -H 'Content-Type: application/json' -d '{"input_url":"<local_folder>/<file>.overall_export_metadata"}'
curl-X POST localhost:/v1/projects/b~:import-H'内容类型:application/json'-d'{“input\u url”:“/.total\u export\u metadata”}”
在本地导入数据存储后,我做了以下变通方法来修复密钥属性。请注意,这并不能解决Google导出错误。我们将需要等待谷歌做到这一点,但同时下面的工作为我。
我创建了一个更新所有键属性的脚本,并在本地交互控制台中运行了该脚本。让Address
成为我们想要更新的数据对象,让Person
成为关键属性引用的数据对象。假设dm
是您的数据模型类,person
是引用的属性。然后可以在Python中执行类似的操作:
from google.appengine.ext import ndb
addresses = dm.Address.query().fetch(None)
for addr in addresses:
if addr.person:
addr.person = ndb.Key('Person', addr.person.id())
addrKeys = ndb.put_multi(addresses)
print 'finished processing {}'.format(len(addrKeys))
对于大型数据集,您需要通过使用分页和游标查询数据集来批量执行此操作。i、 e
DATA_PAGE = 10000
counter = memcache.get('counter')
if not counter:
counter = 0
adr_cursor = memcache.get('adr_cursor')
if adr_cursor:
print('got cursor from mem')
addresses, next_cursor, more = dm.Address.query().fetch_page(DATA_PAGE, start_cursor = adr_cursor)
else:
print('no cursor avail')
addresses, next_cursor, more = dm.Address.query().fetch_page(DATA_PAGE)
# Iterate over the results
for addr in addresses:
if addr.person:
addr.person = ndb.Key('Person', addr.person.id())
counter += 1
ndb.put_multi(addresses)
memcache.set(key="counter", value=counter)
if more and next_cursor:
memcache.set(key="adr_cursor", value=next_cursor)
print 'processed {} more'.format(counter)
else:
print 'finished processing {}'.format(counter)
您需要在交互控制台中按execute,直到处理完所有记录。我为所有受影响的数据集和属性修改并执行了此脚本。发布了清理嵌套的KeyProperties的快速代码,以便在导入数据存储后运行一次
我处理这件事的方式是:
导入时在应用程序id上没有前缀,例如curl-X POST localhost:/v1/projects/:导入
在应用程序id上无前缀运行,例如-A
运行一次处理程序,将KeyProperties更改为正确的开发应用程序id,例如“dev~”+app\u标识。获取应用程序id()
这段代码抽象了一些工作,但是您仍然需要确定哪些实体和属性需要更正。该项目仍在使用webapp2的Python2.7上,因此需要对较新的项目进行一些调整。另外,我强烈建议在更改内容时添加一些日志记录,因为对于大型数据存储来说,这当然需要很长时间
### For changing all of the KeyProperty references inside of an imported
### NDB datastore from production to dev server.
class FixLocalImportHandler(BaseHandler):
devAppID = "dev~" + app_identity.get_application_id()
@staticmethod
def fixAKeyProperty(keyProp):
return ndb.Key(flat = keyProp.flat())
@staticmethod
def fixAModel(modelClass, orderField, attrString, lambdaItem):
chunkSize = 500
chunkOffset = 0
hadAny = True
while hadAny:
hadAny = False
for item in modelClass.query().order(orderField).fetch(offset=chunkOffset, limit=chunkSize):
hadAny = True
needsPut = False
oldAttr = getattr(item, attrString)
# attribute could be a repeated propery, in which case we get a list
# if there's any item with the bad app id, then needs fixing
if isinstance(oldAttr, list):
if len(filter(lambda item: item.app() != FixLocalImportHandler.devAppID, oldAttr)) > 0:
newAttrList = [ndb.Key(flat=oldAttrLi.flat()) for oldAttrLi in oldAttr]
setattr(item, attrString, newAttrList)
needsPut = True
else: # just a single item prop
if oldAttr.app() != FixLocalImportHandler.devAppID:
newAttr = ndb.Key(flat=oldAttr.flat())
setattr(item, attrString, newAttr)
needsPut = True
# hook for additional work that needs to be done for this item (like update a search index)
if(lambdaItem is not None):
lambdaItem(item)
if needsPut:
item.put()
# WATCH INDENT HERE for outer forloop. lol
chunkOffset = chunkOffset + chunkSize
def get(self):
# This code is only for correcting app ids on local test environments
if os.getenv('SERVER_SOFTWARE', '').startswith('Google App Engine/'):
self.display_message("DO NOT ACCIDENTALLY CORRECT LOCAL IMPORT")
return
self.response.headers['Content-Type'] = 'text/plain'
# Call for each entity and KeyProperty field that needs fixing.
FixLocalImportHandler.fixAModel(AModelClass, AModelClass.sortByField, "nameOfFieldToFix", None)
FixLocalImportHandler.fixAModel(AModelClass, AModelClass.sortByField, "anotherNameOfFieldToFix", None)
FixLocalImportHandler.fixAModel(AModelClass2, AModelClass2.sortByField, "nameOfFieldToFix", None)
FixLocalImportHandler.fixAModel(AModelClass2, AModelClass2.sortByField, "anotherNameOfFieldToFix", None)
这是否有助于更正具有KeyProperties的实体?根据我的经验,它不是,但我可能输入错误。假设我的应用程序id是foo,我使用--support\u datastore\u emulator=true--application foo…
本地运行,并使用curl-X POST localhost:/v1/projects/foo:import…
本地实体正确地拥有其密钥.app()
作为dev~foo
但包含KeyProperty的实体仍将s~foo
作为嵌套KeyProperty的键.app()
因此对KeyProperty使用=
的查询不再有效。这是对的@Kelly,如果我像上面那样导入数据存储,那么我就无法从我的本地开发服务器访问它。dev_appserver.py始终在应用程序id前面加上dev~。上述解决方法不适用于我。我尝试指定-A s~,dev_appserver.py创建dev~s~。同意,服务器/导入标志组合不能单独在@lorenc中工作。我处理这个问题的方法是:1)在app idcurl-X POST localhost:/v1/projects/:import
上不带前缀导入,然后2)在app id-A
上不带前缀运行,最后3)编写一些代码将KeyProperties更改为正确的dev app id(“dev~”+app\u identity.get\u application\u id()
)在导入后运行一次。我为此编写的代码并不“很好”,但无论如何,我会在这里的答案中发布它哎呀,我刚看到你已经贴了这个!太好了,很高兴你成功了!