MongoDB结果集在执行查询后被修改

问题描述 投票:4回答:1

在我的应用程序中有2个线程:

  1. 抓取网站并将数据插入MongoDB
  2. 检索已爬网站点并执行业务逻辑

为了检索已爬网站点,我使用以下查询:

Document query = new Document("fetchStatus", new Document("$lte", fetchStatusParam));
FindIterable<Document> unfetchedEpisodes = dbC_Episodes.find(query);

结果我得到了所有剧集,其fetchStatusParam小于或等于特定值。

下一步,我将结果集的项目存储在HashMap<String, TrackedEpisode>中,这是一个对象属性,以便跟踪它们:

for (Document document : unfetchedEpisodes) {
    this.trackedEpisodes.put(document.get("_id").toString(), new TrackedEpisode(document));
}

然后我做了一些业务逻辑,其中:

  • 不修改unfetchedEpisodes结果集。
  • 不会从trackedEpisodes删除任何对象。

到目前为止一切都还可以。 最后一步,我传递所有检索到的文档并将其标记为已获取,以防止将来重复提取。

for (Document document : unfetchedEpisodes) {

    if (this.trackedEpisodes.containsKey(document.get("_id").toString())) {

        // prevent repeated fetching
        document.put("fetchStatus", FetchStatus.IN_PROCESS.getID());

        if (this.trackedEpisodes.get(document.get("_id").toString()).isExpired()) {
            document.put("isExpired", true);
            document.put("fetchStatus", FetchStatus.FETCHED.getID());
        }
    } else {
        System.out.println("BOO! Strange new object detected");
    }

    dbC_Episodes.updateOne(new Document("_id", document.get("_id")), new Document("$set", document));
}

我运行这个代码几天,并注意到有时它到达else语句的if (this.trackedEpisodes.containsKey())部分。这对我来说很奇怪,unfetchedEpisodestrackedEpisodes有可能不同步且不包含相同的项目吗?

我开始研究这个案例,并注意到我到达"BOO! Strange new object detected"的时间document迭代器包含数据库中的项目,但由于我没有对数据库执行新查询,因此不应该在unfetchedEpisodes中。

我检查了几次将检索到的物品存放到trackedEpisodes的问题,并且总是来自unfetchedEpisodes的所有元素都被添加到trackedEpisodes但在此之后我有时仍然会到达"BOO! Strange new object detected"

我的问题:

  1. 为什么unfetchedEpisodes在执行查询后获得新项目?
  2. 执行unfetchedEpisodes后,MongoDB驱动程序是否可能修改Collection#query()
  3. 也许我应该在从MongoDB执行查询后使用.close()

使用的版本:

  1. MongoDB:3.2.3,x64
  2. MongoDB Java驱动程序:mongodb-driver-3.2.2,mongodb-driver-core-3.2.2,bson-3.2.2
java mongodb synchronization
1个回答
2
投票

当你在这里打电话给find时:

FindIterable<Document> unfetchedEpisodes = dbC_Episodes.find(query);

你实际上并没有收到所有的剧集。您正在获取指向匹配文档的数据库游标。

然后当你打电话:

for (Document document : unfetchedEpisodes){}

在与查询匹配的所有文档上创建迭代器。

当您再次调用它时,将为同一查询返回一个新游标,并且迭代现在匹配的所有文档。

如果集合之间发生了变化,结果将会有所不同。

如果你想确保unfetchedEpisodes的内容没有改变,那么你可以将一个选项拉到内存中并在内存中而不是在数据库上迭代它,例如,

ArrayList<Document> unfetchedEpisodes = dbC_Episodes.find(query).into(new ArrayList<Document>());
© www.soinside.com 2019 - 2024. All rights reserved.