Google cloud platform 从Google云数据存储导出将关键属性上的应用程序id设置为b~<;应用程序id>;。这使得进口商品无法使用

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\

我想导出实时数据存储并将其导入到本地数据存储模拟器中,并对其运行测试

由于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\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 id
    curl-X POST localhost:/v1/projects/:import
    上不带前缀导入,然后2)在app id
    -A
    上不带前缀运行,最后3)编写一些代码将KeyProperties更改为正确的dev app id(
    “dev~”+app\u identity.get\u application\u id()
    )在导入后运行一次。我为此编写的代码并不“很好”,但无论如何,我会在这里的答案中发布它哎呀,我刚看到你已经贴了这个!太好了,很高兴你成功了!