【发布时间】:2017-08-11 13:43:18
【问题描述】:
我最近不得不介绍我的数据结构中的更改关于“用户”集合,这导致从以下简化示例迁移:
{
"name": "John",
"emails" : [ "a@a.a", "b@b.b" ]
}
到这里:
{
"name": "John",
"emailAddresses" : [
{
"email" : "a@a.a",
"verified" : true
},
{
"email" : "b@b.b",
"verified" : true
}
]
}
所以“emails”字段从一个简单的字符串数组变成了一个复杂对象的数组,每个对象都有一个“email”和“verified”字段。除此之外,它的名称更改为“emailAddresses”。
我知道如何使用 Morphia 提供的注释(例如 @PostLoad 或 @NotSaved)来迁移我的数据,这些数据涉及使用更改的数据模型进行加载和存储。
我的问题来自于查询。最初,我会通过电子邮件地址查询用户,如下所示:
Query<User> q = dataStore.createQuery(User.class);
q.filter("emails", email);
User u = q.get();
我知道我只需将查询调整为以下内容即可支持我的新数据结构:
Query<User> q = dataStore.createQuery(User.class);
q.filter("emailAddresses.email", email);
User u = q.get();
没关系。问题是我收藏中的一些文档仍然以“旧”方式存储,有些已经以“新”方式存储。如果我只使用“新”方式,我将无法找到旧文档。
问题是:
如何创建一个同时考虑新旧数据的查询 当(如本例中)通过电子邮件地址查询时的结构?
到目前为止,我能想到的最好的办法是使用“或”查询并在禁用验证的情况下查询两个字段(否则抛出异常):
Query<User> q = dataStore.createQuery(User.class);
q.disableValidation();
q.or(q.criteria("emails").equal(email), q.criteria("emailAddresses.email").equal(email));
User u = q.get();
但是,这似乎很麻烦,并且可能不利于性能。 我想知道是否有更好的方法来解决这个问题?
【问题讨论】:
-
为什么不将旧文档更新为新格式?
-
这到底会怎样?我有一个当前使用旧查询的实时运行服务器和一个使用旧数据结构的数据库。如果我更新我的服务器以仅使用新查询,查询将失败,直到例如我运行我的更新脚本。另一方面,如果我先更新数据库再更新服务器,查询也会在短时间内失败。有没有办法在不停机或中断的情况下做到这一点?
-
很公平。问题中没有提到 0 次停机时间。
-
不,不是,我的错。您的建议很好,但考虑到“零停机”因素,您会怎么做?
-
如果没有停机时间,我想除了一些繁琐且缓慢的查询之外别无选择。我过去已经这样做了,然后运行了一些升级代码(迭代所有实体并更改它们的结构 - 不确定是否可以使用标志自动执行此操作),一旦所有内容都迁移到新结构。可能希望在流量较少的情况下这样做。
标签: java mongodb migration database-migration morphia