How to rename a Datastore entity field but be able to retrieve records via old and new property names?

天大地大妈咪最大 提交于 2019-12-24 09:29:02

问题


I have an entity

class Foo {
  public String bar;
}

I want to rename "bar" to "somethingElse". And was planning on using Objectify's @AlsoLoad annotation to achieve that (I am already using Objectify for persistence). So something like:

class Foo {
  @AlsoLoad("bar")
  public String somethingElse;
}

But any queries of the form:

final Query<Foo> query = OfyService.ofy().load().type(Foo.class)
    .filter("somethingElse", "someValue");

Only retrieve entities that have been saved since the rename. Any older entities are ignored.

What is best practice for renaming entity fields so that I can have a single query that will return all records?


回答1:


Note: I'm not an objectify user, the answer is generic, so you'd have to adapt it to objectify specifics.

In general you want to avoid using both bar and somethingElse for extended periods of time, primarily because finding matching entities translates into an OR type of query - .filter("bar", "someValue") OR .filter("somethingElse", "someValue"), which is fundamentally unsupported by the datastore. From Restrictions on queries:

The NOT, OR, and != operators are not natively supported, but some client libraries may add support on top of Cloud Datastore.

This means that, at best, you'd have to jump through hoops to make something like this work, see, for example, Google Datastore combine (union) multiple sets of entity results to achieve OR condition

My suggestion is to perform a one-off migration and be done with it. It would contain the following steps:

  • most likely you'll have to have both properties configured/alive during the migration, so don't just rename bar, instead add somethingElse and don't immediately delete bar
  • in all places where you update the bar property also update somethingElse accordingly
  • add logic to query for all entities which have bar but don't have somethingElse and re-write them so they also have somethingElse. After this step completes all the entities should have a somethingElse mirroring bar
  • in all non-query places where you read bar's value switch to reading somethingElse instead
  • check that all indexes containing somethingElse are serving, then switch your queries from bar to somethingElse. With this the actual migration is complete and you can execute the cleanup steps below
  • drop writing the bar property
  • perform queries for all entitites having a bar property and re-write them without bar. Note that this could be more expensive than actually leaving these entities alone
  • drop bar from your models and indexes (if applicable to your client library), but only if you deleted the property from all your entities in the previous step

A migration following this approach can be performed slowly as it doesn't require complete service shutdown, it can be done live.



来源:https://stackoverflow.com/questions/47615846/how-to-rename-a-datastore-entity-field-but-be-able-to-retrieve-records-via-old-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!