我在数据库中有一个集合“documentDev ”,其切分关键字为“dNumber”样本文档:
{
"_id" : "12831221wadaee23",
"dNumber" : "115",
"processed": false
}
如果我尝试使用任何查询工具更新这个文档,比如-
db.documentDev.update({
"_id" : ObjectId("12831221wadaee23"),
"dNumber":"115"
},{
$set:{"processed": true}},
{ multi: false, upsert: false}
)}`
它会正确更新文档。但是如果我确实使用了Spring boot的mongorepository命令,如DocumentRepo.save(Object),它会引发异常
这是我的文档对象:
@Document(collection = "documentDev")
public class DocumentDev
{
@Id
private String id;
private String dNumber;
private String fileName;
private boolean processed;
}
这是我的知识库类-
@Repository
public interface DocumentRepo extends MongoRepository<DocumentDev,
String> { }
以及我试图更新的值
我尝试执行的函数:
@Autowired
DocumentRepo docRepo;
docRepo.save(doc); // Fails to execute
注意:我在dNumber字段上启用了分片。并且我能够成功地在非关系型数据库工具上使用本机查询进行更新。我还能够在非分片集合上执行存储库保存操作。
更新:我能够通过使用MongoTemplate创建本机查询来更新文档 - 我的查询看起来像这样 -
public DocumentDev updateProcessedFlag(DocumentDev request) {
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(request.getId()));
query.addCriteria(Criteria.where("dNumber").is(request.getDNumber()));
Update update = new Update();
update.set("processed", request.isProcessed());
mongoTemplate.updateFirst(query, update, request.getClass());
return request;
}
但这不是一个通用的解决方案,因为任何其他字段可能都有更新,我的文档也可能有其他字段。
我正在通过创建自定义存储库来破解它:
public interface CosmosCustomRepository<T> {
void customSave(T entity);
void customSave(T entity, String collectionName);
}
此存储库的实现:
public class CosmosCustomRepositoryImpl<T> implements CosmosCustomRepository<T> {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public void customSave(T entity) {
mongoTemplate.upsert(createQuery(entity), createUpdate(entity), entity.getClass());
}
@Override
public void customSave(T entity, String collectionName) {
mongoTemplate.upsert(createQuery(entity), createUpdate(entity), collectionName);
}
private Update createUpdate(T entity) {
Update update = new Update();
for (Field field : entity.getClass().getDeclaredFields()) {
try {
field.setAccessible(true);
if (field.get(entity) != null) {
update.set(field.getName(), field.get(entity));
}
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return update;
}
private Query createQuery(T entity) {
Criteria criteria = new Criteria();
for (Field field : entity.getClass().getDeclaredFields()) {
try {
field.setAccessible(true);
if (field.get(entity) != null) {
if (field.getName().equals("id")) {
return new Query(Criteria.where("id").is(field.get(entity)));
}
criteria.and(field.getName()).is(field.get(entity));
}
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return new Query(criteria);
}
}
您的DocumentRepo
将扩展此新的自定义存储库。
@Repository
public interface DocumentRepo extends MongoRepository<DocumentDev, String>, CosmosCustomRepository<DocumentDev> { }
要保存新文档,只需使用新建自定义保存
@Autowired
DocumentRepo docRepo;
docRepo.customSave(doc);
按照自定义存储库方法,我得到了一个错误,因为spring希望自定义实现{EntityName}CustomRepositoryImpl中有一个Cosmos实体,所以我重命名了该实现。我还添加了以下代码:
>
将生成的 ObjectId 添加到新文档的实体
public class DocumentRepositoryImpl<T> implements CosmosRepositoryCustom<T> {
@Autowired
protected MongoTemplate mongoTemplate;
@Override
public T customSave(T entity) {
WriteResult writeResult = mongoTemplate.upsert(createQuery(entity), createUpdate(entity), entity.getClass());
setIdForEntity(entity,writeResult);
return entity;
}
@Override
public T customSave(T entity, String collectionName) {
WriteResult writeResult = mongoTemplate.upsert(createQuery(entity), createUpdate(entity), collectionName);
setIdForEntity(entity,writeResult);
return entity;
}
@Override
public void customSave(List<T> entities) {
if(CollectionUtils.isNotEmpty(entities)){
entities.forEach(entity -> customSave(entity));
}
}
public <T> Update createUpdate(T entity){
Update update = new Update();
for (Field field : getAllFields(entity)) {
try {
field.setAccessible(true);
if (field.get(entity) != null) {
update.set(field.getName(), field.get(entity));
}
} catch (IllegalArgumentException | IllegalAccessException e) {
LOGGER.error("Error creating update for entity",e);
}
}
return update;
}
public <T> Query createQuery(T entity) {
Criteria criteria = new Criteria();
for (Field field : getAllFields(entity)) {
try {
field.setAccessible(true);
if (field.get(entity) != null) {
if (field.getName().equals("id")) {
Query query = new Query(Criteria.where("id").is(field.get(entity)));
query.addCriteria(new Criteria(SHARD_KEY_NAME).is(SHARD_KEY_VALUE));
return query;
}
criteria.and(field.getName()).is(field.get(entity));
}
} catch (IllegalArgumentException | IllegalAccessException e) {
LOGGER.error("Error creating query for entity",e);
}
}
return new Query(criteria);
}
private <T> List<Field> getAllFields(T entity) {
List<Field> fields = new ArrayList<>();
fields.addAll(Arrays.asList(entity.getClass().getDeclaredFields()));
Class<?> c = entity.getClass().getSuperclass();
if(!c.equals(Object.class)){
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
public <T> void setIdForEntity(T entity,WriteResult writeResult){
if(null != writeResult && null != writeResult.getUpsertedId()){
Object upsertId = writeResult.getUpsertedId();
entity.setId(upsertId.toString());
}
}
}
我使用的是spring boot starter mongodb:1.5.1和spring数据mongodb:1.9.11
我有同样的问题,通过以下黑客解决:
@Configuration
public class ReactiveMongoConfig {
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate(ReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory,
MongoConverter converter, MyService service) {
return new ReactiveMongoTemplate(reactiveMongoDatabaseFactory, converter) {
@Override
protected Mono<UpdateResult> doUpdate(String collectionName, Query query, UpdateDefinition update,
Class<?> entityClass, boolean upsert, boolean multi) {
query.addCriteria(new Criteria("shardKey").is(service.getShardKey()));
return super.doUpdate(collectionName, query, update, entityClass, upsert, multi);
}
};
}
}
最好有一个注释@ShardKey将文档字段标记为分片并将其自动添加到查询中。
有人知道在Mongo3中更新封顶收藏的方法吗。2.我让它在2分钟内工作。我更新了一个收藏,基本上删除了它的所有内容,所以我知道它已经被处理过了。这样就会过时。 当我在3.2中执行同样的操作时,我在命令行上会出现以下错误。 无法更改封顶集合中文档的大小:318!=40 在这里,你可以看到我正在将文档从318字节缩减到40字节。 有办法做到这一点吗?
我们有一个相对简单的分片MongoDB设置:4个分片,每个分片是一个副本集,至少有3个成员。每个集合都由从大量文件加载的数据组成;每个文件都被赋予一个单调递增的ID,并且根据ID的哈希完成分片。 我们的大部分产品都在按预期工作。然而,我有一个集合似乎没有正确地将块分布到各个碎片上。在创建索引之前,集合加载了大约30GB的数据,并且进行了分片,但是据我所知,这并不重要。以下是该集合的统计数据: 这个
主要内容:MongoDB 中的分片,分片实例分片是跨多台机器存储数据的过程,它是 MongoDB 满足数据增长需求的方法。随着数据的不断增加,单台机器可能不足以存储全部数据,也无法提供足够的读写吞吐量。通过分片,您可以添加更多计算机来满足数据增长和读/写操作的需求。 为什么要分片? 在复制中,所有写操作都将转到主节点; 对延迟敏感的查询仍会转到主查询; 单个副本集限制为 12 个节点; 当活动数据集很大时,会出现内存不足; 本地磁盘不够大;
我在localhost上设置了一个分片的mongo db环境,有3个配置服务器、2个分片的mongo实例和一个mongos。 集群启动后,我运行以下命令序列: 我启用数据库进行分片,并创建一个索引等。 以上所有操作的结果都是成功的。 但是一旦我做到了:db.foo.stats() 我看到所有的数据都在一个分片中结束,而没有被分发。和运行 生产: 然而,有趣的是,如果我从一个空白集合开始,并在向其中
我使用Spring Boot和Spring Data MongoDB与底层分片MongoDB集群进行接口。我的Spring Boot应用程序通过路由器访问集群。 使用Spring Data MongoDB,可以通过指定对象持久化到的集合,或者默认为类名(第一个字母小写)。这些藏品不需要预先存在;它们可以在运行时创建。 要在MongoDB中分片集合,您需要 1-在数据库上启用分片: 2-在分片数据库
我想从配置文件中部署一个mongodb副本集,该副本集包含1个主副本和2个次副本,如下所示: 主节点的第一个配置文件 我也得到了同样的错误 我不知道我需要做什么esle配置来解决这个问题,请帮助我,非常感谢。