You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB Async Driver Java检查记录存在性失效,求高效实现方法

使用MongoDB Async Driver高效检查记录存在性的解决方案

先说说你当前代码的问题所在——这也是插入逻辑没执行的核心原因:

  1. MongoDB Async Driver的find()方法返回的是FindIterable对象,永远不会是null,所以你写的==null判断永远不成立,自然跳不到插入逻辑。
  2. limit(0)会强制查询返回0条结果,这完全违背了你“检查记录是否存在”的初衷。

接下来给你两种高效的实现方式,以及高并发场景下的原子性方案:

方法1:用countDocuments()(简洁直观)

这种方式直接统计匹配查询条件的文档数量,只要数量为0就说明记录不存在。因为是异步操作,要通过CompletableFuture的回调来处理结果:

// 构造你的查询条件,比如按某个唯一字段查询
Bson filter = Filters.eq("username", "patoCapongo93");

collection.countDocuments(filter)
    .thenAccept(count -> {
        if (count == 0) {
            // 记录不存在,执行插入
            Document newUser = new Document("username", "patoCapongo93")
                .append("email", "example@test.com");
            collection.insertOne(newUser)
                .thenRun(() -> System.out.println("新文档插入成功"))
                .exceptionally(e -> {
                    System.err.println("插入失败:" + e.getMessage());
                    return null;
                });
        }
    })
    .exceptionally(e -> {
        System.err.println("计数查询失败:" + e.getMessage());
        return null;
    });

方法2:用findOne()(性能更优)

如果只是判断存在性,findOne()会在找到第一条匹配的文档后立即终止查询,不需要统计所有匹配的数量,在数据量较大时性能更好。另外可以指定只返回_id字段,减少网络传输的数据量:

Bson filter = Filters.eq("username", "patoCapongo93");
// 只查询_id字段,降低网络开销
Bson projection = Projections.include("_id");

collection.findOne(filter, projection)
    .thenAccept(existingDoc -> {
        if (existingDoc == null) {
            // 记录不存在,执行插入
            Document newUser = new Document("username", "patoCapongo93")
                .append("email", "example@test.com");
            collection.insertOne(newUser)
                .thenRun(() -> System.out.println("新文档插入成功"))
                .exceptionally(e -> {
                    System.err.println("插入失败:" + e.getMessage());
                    return null;
                });
        }
    })
    .exceptionally(e -> {
        System.err.println("查询失败:" + e.getMessage());
        return null;
    });

高并发场景:原子性“不存在则插入”

如果你的场景存在并发写入,上面的两种方法可能会出现竞态条件(比如两个请求同时判断记录不存在,然后都执行插入)。这种情况下更推荐使用以下两种方案:

方案1:使用replaceOne原子操作

Document newUser = new Document("username", "patoCapongo93")
    .append("email", "example@test.com");

collection.replaceOne(
    Filters.eq("username", "patoCapongo93"),
    newUser,
    new ReplaceOptions().upsert(true)
).thenAccept(result -> {
    if (result.getUpsertedId() != null) {
        System.out.println("文档是新插入的");
    } else {
        System.out.println("文档已存在,执行了更新");
    }
}).exceptionally(e -> {
    System.err.println("操作失败:" + e.getMessage());
    return null;
});

方案2:唯一索引+insertOne

先给查询字段创建唯一索引:

collection.createIndex(Indexes.ascending("username"), new IndexOptions().unique(true));

之后直接执行insertOne,如果记录已存在会抛出MongoWriteException,你可以捕获这个异常来处理已存在的情况:

Document newUser = new Document("username", "patoCapongo93")
    .append("email", "example@test.com");

collection.insertOne(newUser)
    .thenRun(() -> System.out.println("新文档插入成功"))
    .exceptionally(e -> {
        if (e instanceof MongoWriteException && ((MongoWriteException) e).getError().getCode() == 11000) {
            System.out.println("文档已存在");
        } else {
            System.err.println("插入失败:" + e.getMessage());
        }
        return null;
    });

内容的提问来源于stack exchange,提问作者patoCapongo93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:46:00