我对MongoDB相对较新,但我们考虑将其用作遗留服务前的某种缓存。在这种情况下,我们偶然发现了一些问题。
首先,一些解释。
此缓存服务将位于旧服务和客户端之间。客户端将连接到缓存服务,缓存服务从旧服务获取其数据。缓存服务每X分钟获取一次数据,并将它们保存在MongoDB中。模式非常简单:只需要一个包含大量键/值的文档。没有嵌套文件等。此外,我们将_id设置为旧服务中的唯一ID,因此我们也可以对此进行控制。
当缓存服务从旧服务获取数据时,它只获得一个增量(仅自上次获取后更改)。因此,如果自上次以来5个“对象”发生了变化,那么你只得到那些5个“对象”(但是你得到了完整的对象,而不是对象的三角形)。如果遗留服务中添加了任何新的“对象”,那么这些对象当然也在增量中。
我们的“问题”
在我看来,这听起来像一个甜头。如果有新对象,请插入它们。如果现有对象发生更改,请更新它们。但是,MongoDB似乎并不特别喜欢多次upsert。只是插入给我一个关于重复键的错误,这是完全可以理解的,因为文档已经存在与相同的_id。 update函数可以采用upsert参数,不能获取新对象列表。在我看来,单个查询是不可能的。但是,我可能完全忽视了这里的一些东西。
可能的解决方案
有许多不同的解决方案,尤其是我想到的两个解决方案:
对于提出的两个解决方案和任何其他解决方案,我们将非常感谢任何帮助。作为旁注,技术不是真正可以讨论的,所以请不要建议其他类型的数据库或语言。为什么我们选择了我们选择的东西还有其他强大的理由:)
答案 0 :(得分:1)
我会分享我的经验......
在我上一份工作中,我们遇到了类似的情况。我们最终为每个文档/对象执行一次查询/写入。我们使用Mule ESB将遗留系统中的数据抽取到Mongo,每次写入都是upsert。
表现相当不错,但不是很好。我们可以在几分钟内将几千份文件送入Mongo。这些文件相当丰富,这可能是我们为什么不得不限制对Mongo的写入的一部分。
在我们批量加载数据后,“实时”性能从来都不是问题。
您建议的第一个选项听起来太复杂,并且可能会使Mongo处于未知状态,以防操作在更新中途中止。 upsert选项保存了很多次,因为我们可以反复重放插件并且安全。
答案 1 :(得分:1)
扩展ryan1234的答案:
2.6版本的MongoDB将能够发送批量更新。现在,您需要为每个文档提交单独的请求。
正如ryan1234所说,对每个文档执行upsert是更新所有现有文档并添加新文档的唯一安全方法,如果您不知道旧版提供程序。单个MongoDB进程可以在中间硬件上轻松处理每秒数千次更新(1)。如果您没有达到该级别的性能,那么可能是客户端和MongDB服务器之间的请求延迟。 Asynchronous Java Driver可以帮助克服这一限制,允许多个更新请求同时传输到服务器,同时最小化客户端复杂性/线程。
HTH,Rob
1:我认为文档没有增长,没有索引更新,但即使是那些你应该能够每秒接近一千个更新。
答案 2 :(得分:1)
如果你的钥匙是复合的,你可以使用:
public static BulkWriteResult insertAll(MongoCollection<Document> coll, List<Document> docs, String[] keyTags, boolean upsert) {
if(docs.isEmpty())
return null;
List<UpdateOneModel<Document>> requests = new ArrayList<>(docs.size());
UpdateOptions opt = new UpdateOptions().upsert(upsert);
for (Document doc : docs ) {
BasicDBObject filter = new BasicDBObject();
for (String keyTag : keyTags) {
filter.append(keyTag, doc.get(keyTag));
}
BasicDBObject action = new BasicDBObject("$set", doc);
requests.add(new UpdateOneModel<Document>(filter, action, opt));
}
return coll.bulkWrite(requests);
}
答案 3 :(得分:0)
我知道。它必须真正深入挖掘正确的方法。 试试这个: / ** *将文档中的所有项目插入到集合中。 * @param coll目标集合 * @param提供新的或更新的文档 * @param keyTag文档中键的名称 * @param upsert if true如果未找到则创建新文档 * @return BulkWriteResult如果docs.isEmpty()则为null * /
public static BulkWriteResult insertAll(MongoCollection<Document> coll, List<Document> docs, String keyTag, boolean upsert) {
if(docs.isEmpty())
return null;
List<UpdateOneModel<Document>> requests = new ArrayList<>(docs.size());
UpdateOptions opt = new UpdateOptions().upsert(upsert);
for (Document doc : docs ) {
BasicDBObject filter = new BasicDBObject(keyTag, doc.get(keyTag));
BasicDBObject action = new BasicDBObject("$set", doc);
requests.add(new UpdateOneModel<Document>(filter, action, opt));
}
return coll.bulkWrite(requests);
}