解决runCommand只查询到101条数据

4 篇文章 0 订阅
3 篇文章 0 订阅

最近在开发中使用runCommand查询数据时,发现每次返回的数据量都是101条,而我需要查询的是全部的数据,带着问题,扒了一下runCommand数据查询操作的官方文档,得到了问题的答案。

准备运行环境

MongoClient

这里我是用的Mongo驱动是3.4.3版本的(目前项目中使用的是这个驱动);

ServerAddress serverAddress = new ServerAddress("127.0.0.1", 27017);
MongoClientOptions mongoClientOptions = MongoClientOptions.builder().build();
MongoCredential mongoCredential = MongoCredential.createCredential("username", "db", "password".toCharArray());

MongoClient mongoClient = new MongoClient(Collections.singletonList(serverAddress),
        Collections.singletonList(mongoCredential), mongoClientOptions);

代码中使用mongodb地址、库、用户名、密码等信息创建了MongoClient对象

初始化数据

MongoClient对象创建完成后,我们使用单元测试向MongoDB库的test集合中批量插入1024条数据

@Test
public void testInsert() {
    MongoDatabase database = mongoClient.getDatabase("db");

    BasicDBObject basicDBObject = new BasicDBObject();
    basicDBObject.put("insert", "test");

    BasicDBList dbList = new BasicDBList();
    for(int i = 1; i <= 1024; i ++) {
        BasicDBObject document = new BasicDBObject();
        document.put("_id", i);
        document.put("name", "name_" + i);
        dbList.add(document);
    }

    basicDBObject.put("documents", dbList);
    database.runCommand(basicDBObject);
}

问题复现

编写了一个与线上查询逻辑一致的单元测试用例进行问题复现

@Test
public void testFindWithQuestion() {
    MongoDatabase database = mongoClient.getDatabase("db");

    BasicDBObject basicDBObject = new BasicDBObject();
    basicDBObject.put("find", "test");
    BasicDBObject projection = new BasicDBObject();
    projection.put("_id", 1);
    basicDBObject.put("projection", projection);
    Document document = database.runCommand(basicDBObject);

    double ok = document.getDouble("ok");
    if(1 == ok) {
        Document cursor = document.get("cursor", Document.class);
        if(cursor.containsKey("firstBatch")) {
            List<Document> documentList = cursor.get("firstBatch", List.class);
            System.out.println(documentList);
            System.out.println(documentList.size());
        }
    }
}

单元测试执行完之后打印了一下数据条数,结果真的是101条,与线上问题一致:

解决问题

问题来源

带着问题去MongoDB官方文档中查询find操作命令相关的文档:

find — MongoDB Manual

在文档中查找到了batchSize参数,是这样描述的:

此参数用于指定firstBatch中返回的文档数量,默认是101;

看到这里终于明白为什么查询时返回的文档数量是101了,那么接下来的问题就是如何查询到全部的文档。

解决办法

带着问题,继续看文档,最终看到了Output返回参数的介绍。

返回的字段中包含了cursor字段,cursor字段中包含了游标编号和fisrtBatch文档;文档中强调了可以使用getMore命令查询剩余的文档。

getMore文档地址getMore — MongoDB Manual

getMore命令可以和返回游标的命令结合使用,可用于查询find命令或者aggregate命令的游标指向文档的后续批次文档。到这里基本上是找到了如何解决问题的答案。

代码实现

@Test
public void testFind() {
    MongoDatabase database = mongoClient.getDatabase("db");

    BasicDBObject basicDBObject = new BasicDBObject();
    basicDBObject.put("find", "test");
    BasicDBObject projection = new BasicDBObject();
    projection.put("_id", 1);
    basicDBObject.put("projection", projection);
    boolean hasNext = true;
    do {
        Document document = database.runCommand(basicDBObject);
        MongoDocumentList mongoDocumentList = resolveDocument(document);
        System.out.println(mongoDocumentList.documentList);
        System.out.println(mongoDocumentList.documentList.size());
        hasNext = mongoDocumentList.hasNext();
        if(hasNext) {
            basicDBObject = new BasicDBObject();
            basicDBObject.put("getMore", mongoDocumentList.cursor);
            basicDBObject.put("collection", "test");
        }
    } while (hasNext);
}

private MongoDocumentList resolveDocument(Document document) {
    double ok = document.getDouble("ok");
    if(1 == ok) {
        Document cursor = document.get("cursor", Document.class);
        List<Document> documentList = null;
        if(cursor.containsKey("firstBatch")) {
            documentList = cursor.get("firstBatch", List.class);
        } else if (cursor.containsKey("nextBatch")) {
            documentList = cursor.get("nextBatch", List.class);
        }

        return new MongoDocumentList(cursor.getLong("id"), documentList);
    }
    return null;
}

@AllArgsConstructor
private static class MongoDocumentList {
    private Long cursor;
    private List<Document> documentList;

    public boolean hasNext() {
        return 0 != cursor;
    }
}

代码中定义了MongoDocumentList实体,用于封装每次查询的结果,代码中判断查询是否结束是根据getMore命令返回的数据中的cursor编号是否为0进行判断的。

执行单元测试的结果如下:

查询的总数据量刚好是1024条

  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值