当前位置: 首页 > 知识库问答 >
问题:

在java中使用mongodb游标(DBCursor)的罕见行为,即使已经到达最后一个元素

扈沛
2023-03-14

我有一个名为My集合的集合,其中包含mongodb中bd MyDB中的200个元素

> use MyDB
switched to db MyDB 
> db.MyCollection.count()
200

我得到了一个非常罕见的行为,即使是在我用来加载光标并在其上迭代的不同方式中,这是我的代码:

DBCollection collection = getCollection("MyBD", "MyCollection");
DBCursor cursor = collection.find();
//DBCursor cursor = collection.find().limit(200); 
System.out.println("Cursor length: "+cursor.length());
Iterator<DBObject> itrc = cursor.iterator();
//while(cursor.hasNext()){
while (itrc.hasNext()) {
    //DBObject obj = (DBObject)cursor.next();
    DBObject obj = (DBObject)itrc.next();
    //BSONObject obj2 = (BSONObject)obj.get("scores");
    Integer intg = (Integer) obj.get("_id");
    System.out.println("_id:"+intg.toString());

    // operations remove and insert  on the collection
    // that affect the cursor behavior
    BasicDBList bl = (BasicDBList) obj.get("fieldArray");
    BasicDBObject bdo = new BasicDBObject();
    bdo.put("fieldArray", bl);
    Integer intid = (Integer) obj.get("_id");
    bdo.put("_id", intid);
    String str = (String) obj.get("fieldString");
    bdo.put("fieldString", str);
    collection.remove(obj);
    obj=null;
    collection.insert(bdo);

    if(intg.intValue()==199){
        System.out.println("Reached: "+intg.intValue());
    }   
}

这是输出:

Cursor length: 200
_id:0 _id:1 _id:2 _id:3 _id:4 _id:5 _id:6 _id:7 _id:8 _id:9 _id:10 _id:11 _id:12 _id:13 _id:14 _id:15 _id:16 _id:17 _id:18 _id:19 _id:20 _id:21 _id:22 _id:23 _id:24 _id:25 _id:26 _id:27 _id:28 _id:29 _id:30 _id:31 _id:32 _id:33 _id:34 _id:35 _id:36 _id:37 _id:38 _id:39 _id:40 _id:41 _id:42 _id:43 _id:44 _id:45 _id:46 _id:47 _id:48 _id:49 _id:50 _id:51 _id:52 _id:53 _id:54 _id:55 _id:56 _id:57 _id:58 _id:59 _id:60 _id:61 _id:62 _id:63 _id:64 _id:65 _id:66 _id:67 _id:68 _id:69 _id:113 _id:101 _id:102 _id:103 _id:104 _id:105 _id:106 _id:107 _id:108 _id:109 _id:110 _id:111 _id:112 _id:114 _id:115 _id:116 _id:117 _id:118 _id:119 _id:120 _id:121 _id:122 _id:123 _id:124 _id:125 _id:126 _id:127 _id:128 _id:129 _id:130 _id:131 _id:132 _id:133 _id:134 _id:135 _id:136 _id:137 _id:138 _id:139 _id:140 _id:141 _id:142 _id:143 _id:144 _id:145 _id:146 _id:147 _id:148 _id:149 _id:150 _id:151 _id:152 _id:153 _id:154 _id:155 _id:156 _id:157 _id:158 _id:159 _id:160 _id:161 _id:162 _id:163 _id:164 _id:165 _id:166 _id:167 _id:168 _id:169 _id:170 _id:171 _id:172 _id:173 _id:174 _id:175 _id:176 _id:177 _id:178 _id:179 _id:180 _id:181 _id:182 _id:183 _id:184 _id:185 _id:186 _id:187 _id:188 _id:189 _id:190 _id:191 _id:192 _id:193 _id:194 _id:195 _id:196 _id:197 _id:198 _id:199
***************************
Reached: 199
***************************
 _id:70 _id:71 _id:72 _id:73 _id:74 _id:75 _id:76 _id:77 _id:78 _id:79 _id:80 _id:81 _id:82 _id:83 _id:84 _id:85 _id:86 _id:87 _id:88 _id:89 _id:90 _id:91 _id:92 _id:93 _id:94 _id:95 _id:96 _id:97 _id:98 _id:99 _id:100_id:96 _id:97 _id:98 _id:99 _id:100

如图所示,一旦达到200个元素的限制(元素_id:199),它跳到元素_id:70,然后重复31次额外的迭代,直到达到元素_id:100,而不是在200次迭代的正确时间完成。

备选方案:在代码中被注释的一个(使用游标的方法:hasNext())和正在运行的另一个(使用迭代器)都有相同的输出。

如果我删除集合上的操作部分(在我的情况下是删除/插入),那么不会发生罕见的行为。

这是预期输出:

Cursor length: 200
_id:0 _id:1 _id:2 _id:3 _id:4 _id:5 _id:6 _id:7 _id:8 _id:9 _id:10 _id:11 _id:12 _id:13 _id:14 _id:15 _id:16 _id:17 _id:18 _id:19 _id:20 _id:21 _id:22 _id:23 _id:24 _id:25 _id:26 _id:27 _id:28 _id:29 _id:30 _id:31 _id:32 _id:33 _id:34 _id:35 _id:36 _id:37 _id:38 _id:39 _id:40 _id:41 _id:42 _id:43 _id:44 _id:45 _id:46 _id:47 _id:48 _id:49 _id:50 _id:51 _id:52 _id:53 _id:54 _id:55 _id:56 _id:57 _id:58 _id:59 _id:60 _id:61 _id:62 _id:63 _id:64 _id:65 _id:66 _id:67 _id:68 _id:69 _id:113 _id:101 _id:102 _id:103 _id:104 _id:105 _id:106 _id:107 _id:108 _id:109 _id:110 _id:111 _id:112 _id:114 _id:115 _id:116 _id:117 _id:118 _id:119 _id:120 _id:121 _id:122 _id:123 _id:124 _id:125 _id:126 _id:127 _id:128 _id:129 _id:130 _id:131 _id:132 _id:133 _id:134 _id:135 _id:136 _id:137 _id:138 _id:139 _id:140 _id:141 _id:142 _id:143 _id:144 _id:145 _id:146 _id:147 _id:148 _id:149 _id:150 _id:151 _id:152 _id:153 _id:154 _id:155 _id:156 _id:157 _id:158 _id:159 _id:160 _id:161 _id:162 _id:163 _id:164 _id:165 _id:166 _id:167 _id:168 _id:169 _id:170 _id:171 _id:172 _id:173 _id:174 _id:175 _id:176 _id:177 _id:178 _id:179 _id:180 _id:181 _id:182 _id:183 _id:184 _id:185 _id:186 _id:187 _id:188 _id:189 _id:190 _id:191 _id:192 _id:193 _id:194 _id:195 _id:196 _id:197 _id:198 _id:199
***************************
Reached: 199
***************************

我曾发现一个类似如此的问题,但我并不清楚:

  • 操作删除/插入如何以我之前公开的方式影响光标行为?
  • 如何使用快照选项?
  • 提前考虑,如果我需要使用有序集合怎么办?

顺便说一句,如果我使用不带迭代器的选项,如下所示:

while(cursor.hasNext()){
    DBObject obj = (DBObject)cursor.next();

>

  • 为什么我必须删除下一行?

    System.out.println("光标长度:"cursor.length());

    为了避免下一个例外:

    Exception in thread "main" java.lang.IllegalArgumentException: can't switch cursor access methods
        at com.mongodb.DBCursor._checkType(DBCursor.java:412)
        at com.mongodb.DBCursor.hasNext(DBCursor.java:483)
        at tasks.UpdateRemoveHW.main(Test.java:56)
    
  • 共有2个答案

    严瀚昂
    2023-03-14

    我不确定你在问题的第一部分中的罕见行为发生了什么,但是一般来说,在迭代任何数据结构时修改它是不安全的,除非通过Iterator.remove()方法。

    问题的最后一部分由 DBCursor API 文档顶部的以下警告间接回答:

    警告:调用toArray或DBCousor上的长度将不可逆转地将其转换为数组。这意味着,如果游标正在迭代超过一千万个结果(它是懒惰地从数据库中获取的),内存中会突然出现一千万个元素数组。在转换为数组之前,请使用跳过()和限制()确保有合理数量的结果。

    如果你阅读DBCursor的源代码(第483行),其中抛出IllegalArgumentException,你可以看到任何对DBCursor.length()的调用都会将光标变成一个数组,之后所有对DBCursor.next()或DBCursor.hasNext()的调用都变成非法的。

    我认为这种行为绝对违反了最小惊喜原则。数组仍然可以有迭代器,所以如果内部数据结构被隐藏并且迭代器方法继续工作会更好。此外,调用DBCursor.length()不必从数据库中获取任何记录,我认为它应该表现得类似于DBCursor.count(),但以某种方式考虑限制()和跳过(),然后缓存结果。

    蔚楷
    2023-03-14

    只需抛出异常IllegalArgumentException,然后您会发现使用DBCursor.length()已经将curser转换为一个数组。所以在那之后使用hasnext(),next就是illegegal。如果想在迭代前用hasnext()或者next()更好的去掉length()。

     类似资料:
    • 在Java 7中,如果我想得到一个列表的最后一个非空元素,我会这样写: 我想通过使用 lambdas 或 Java 8 的其他功能来编写一个更短的代码。例如,如果我想得到第一个非空元素,我可以这样写: 也许有人知道如何解决这个问题?

    • 我在Mongo DB Atlas中收集了一个用户名称。 它还在继续。 在节点中可以使用什么查询。js和mongoose找到集合中的最后一个元素了吗?当集合不断动态增加时,如何获取集合最后一个元素的id?

    • 例如,我的Android应用程序中有消息元素,所有这些元素都有一个名为“message_view”的资源ID。我想要的是仅使用Xpath获得带有这个资源ID的最后一条消息。我尝试使用,但它不起作用: 我知道我可以使用,然后使用。但我想了解如何仅使用Xpath来完成此操作。

    • 本文向大家介绍在Scala中找到列表的最后一个元素,包括了在Scala中找到列表的最后一个元素的使用技巧和注意事项,需要的朋友参考一下 假设我们在Scala中有一个列表,该列表在scala.collection.immutable包下定义。众所周知,列表是相同类型元素的集合,其中包含不可变(不可更改)数据。我们通常应用last函数来显示列表的最后一个元素。 使用最后一个关键字 以下Scala代码显

    • 本文向大家介绍如何使用jQuery作为最后一个子元素插入元素?,包括了如何使用jQuery作为最后一个子元素插入元素?的使用技巧和注意事项,需要的朋友参考一下 要使用jQuery将元素作为最后一个子元素插入,请使用方法。append(content)方法将内容附加到每个匹配元素的内部。 示例 您可以尝试运行以下代码,以了解如何使用jQuery作为最后一个子元素插入元素:

    • 我正在做我的项目,然后我需要Json数据中的reach an元素看起来像: 因此,我可以用以下方法访问name元素: 那么,如何在java 8中使用stream()到达学校呢? 还有,我调用的< code>getName();