如果封顶集合达到最大大小,为什么MongoDB不会删除旧文档?

时间:2014-09-12 07:59:18

标签: java mongodb exception capped-collections

我有一个上限集合,它是用java代码创建的:

this.collection = db.createCollection("stat", new BasicDBObject("capped", true).append("size", 200000000).append("max", 1000000));

现在有关此系列的统计数据,我们有:

/* 0 */
{
    "ns" : "myDatabase.stat",
    "count" : 12212,
    "size" : 2146416,
    "avgObjSize" : 175,
    "storageSize" : 200003584,
    "numExtents" : 1,
    "nindexes" : 4,
    "lastExtentSize" : 200003584,
    "paddingFactor" : 1,
    "systemFlags" : 1,
    "userFlags" : 0,
    "totalIndexSize" : 2272928,
    "indexSizes" : {
        "_id_" : 1259104,
        "downloaded_1" : 335216,
        "submitted_1" : 318864,
        "retries_1" : 359744
    },
    "capped" : true,
    "max" : 1000000,
    "ok" : 1
}

如果我尝试使用此代码在集合中插入文档:

BasicDBObject doc = new BasicDBObject().
        append("downloaded", new Date(0)).
        append("sessionId", sessionId).
        append("group", group);
collection.update(new BasicDBObject("_id", request.getUrl()), new BasicDBObject("$set", doc), true, false);

我发现了这个错误:

com.mongodb.WriteConcernException: { "serverUsed" : "/127.0.0.1:27017" , "lastOp" : { "$ts" : 0 , "$inc" : 0} , "connectionId" : 16420 , "err" : "failing update: objects in a capped ns cannot grow" , "code" : 10003 , "n" : 0 , "ok" : 1.0}
        at com.mongodb.CommandResult.getException(CommandResult.java:77)
        at com.mongodb.CommandResult.throwOnError(CommandResult.java:110)
        at com.mongodb.DBTCPConnector._checkWriteError(DBTCPConnector.java:102)
        at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:142)
        at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:115)
        at com.mongodb.DBApiLayer$MyCollection.update(DBApiLayer.java:327)
        at com.mongodb.DBCollection.update(DBCollection.java:178)
        at com.mongodb.DBCollection.update(DBCollection.java:209)
        at com.srg.hydra.monitoring.HydraStatistics.insert(HydraStatistics.java:63)
        at com.srg.hydra.HydraSite.onSubmit(HydraSite.java:91)
        at ru.decipher.site.AbstractSite.submit(AbstractSite.java:198)
        at com.srg.hydra.Eip.start(Eip.java:48)
        at com.srg.hydra.runner.DefaultHydraRunner.doCrawling(DefaultHydraRunner.java:180)
        at com.srg.hydra.runner.DefaultHydraRunner$1.run(DefaultHydraRunner.java:155)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

我做错了什么?以及如何解决它? (不包括.drop()此集合并重新创建) 谢谢你的回答!

1 个答案:

答案 0 :(得分:1)

您无法更新上限集合中的文档。(如果您阅读完整的答案,可以使用此方法。)我以前遇到过这个问题。请从以下MongoDB文档中找到此问题的详细信息(和解决方案):

建议和限制

  
      
  • 您只能对文档进行就地更新。如果更新操作导致文档增长超过其原始大小,则更新操作将失败。

  •   
  • 如果您计划更新上限集合中的文档,请创建索引,以便这些更新操作不需要进行表扫描。

  •   
  • 如果您将封顶集合中的文档更新为小于其原始大小的文档,然后从主节点更新辅助重新同步,则辅助节点将根据当前较小的文档大小进行复制并分配空间。如果主数据库接收到将文档恢复为原始大小的更新,则主数据库将接受更新,但辅助数据库将因更新失败而失败:上限ns中的对象无法增加错误消息。

  •   
  • 要防止出现此错误,请从副本集的其他最新成员的快照创建辅助节点。按照我们的文件系统快照教程为您的新辅助设备播种。

  •   
  • 使用文件系统快照为辅助节点播种是保证主要和辅助二进制文件兼容的唯一方法。在这种情况下,MMS备份快照不足,因为您需要的次数超过次要内容以匹配主要内容。

  •   
  • 您无法从上限集合中删除文档。要从有上限的集合中删除所有记录,请使用'emptycapped'命令。要完全删除集合,请使用drop()方法。

  •   
  • 您无法对上限集合进行分片。

  •   
  • 2.2之后创建的上限集合默认情况下在_id字段上有_id字段和索引。在2.2之前创建的上限集合默认情况下在_id字段上没有索引。如果使用带有2.2之前复制的上限集合,则应在_id字段上显式创建索引。

  •