mongodb - 什么是 MongoDB 中的光标?

标签 mongodb mongodb-query database-cursor

我们对某些 Morphia 查询最终出现 cursor not found 异常 感到困扰 asList我找到了 hint on SO ,这可能会非常消耗内存。

现在我想了解更多关于背景的信息:有人能解释一下(用英语),Cursor(在 MongoDB 中)到底是什么吗?为什么它可以一直打开或找不到?


文档 defines光标为:

A pointer to the result set of a query. Clients can iterate through a cursor to retrieve results. By default, cursors timeout after 10 minutes of inactivity

但这不是很能说明问题。也许为查询结果定义一个 batch 可能会有所帮助,因为 documentation also states :

The MongoDB server returns the query results in batches. Batch size will not exceed the maximum BSON document size. For most queries, the first batch returns 101 documents or just enough documents to exceed 1 megabyte. Subsequent batch size is 4 megabytes. [...] For queries that include a sort operation without an index, the server must load all the documents in memory to perform the sort before returning any results.

注意:在我们所讨论的查询中,我们根本不使用排序语句,也没有使用 limitoffset

最佳答案

以下是 Node.js MongoDB 驱动程序中 toArray()find() 之后的游标之间的比较。常用代码:

var MongoClient = require('mongodb').MongoClient,
assert = require('assert');

MongoClient.connect('mongodb://localhost:27017/crunchbase', function (err, db) {
    assert.equal(err, null);
    console.log('Successfully connected to MongoDB.');

    const query = { category_code: "biotech" };

    // toArray() vs. cursor code goes here
});

这里是 toArray()上一节中的代码。

    db.collection('companies').find(query).toArray(function (err, docs) {
        assert.equal(err, null);
        assert.notEqual(docs.length, 0);

        docs.forEach(doc => {
            console.log(`${doc.name} is a ${doc.category_code} company.`);
        });

        db.close();
    });

根据文档,

The caller is responsible for making sure that there is enough memory to store the results.

这是基于光标的方法,使用 cursor.forEach()方法:

    const cursor = db.collection('companies').find(query);

    cursor.forEach(
        function (doc) {
            console.log(`${doc.name} is a ${doc.category_code} company.`);
        },
        function (err) {
            assert.equal(err, null);
            return db.close();
        }
    );
});

使用 forEach() 方法,我们不是在内存中获取所有数据,而是将数据流式传输到我们的应用程序。 find() 立即创建一个游标,因为它实际上不会向数据库发出请求,直到我们尝试使用它将提供的一些文档。 cursor 的重点是描述我们的查询。 cursor.forEach 的第二个参数显示了发生错误时的处理方式。

在上述代码的初始版本中,是 toArray() 强制数据库调用。这意味着我们需要 ALL 文档并希望它们位于 array 中。

注意 MongoDB 是分批返回数据的。下图显示了从游标(从应用程序)到 MongoDB 的请求:

MongoDB cursor graphic

forEachtoArray 具有更好的扩展性,因为我们可以在文档进入时处理,直到到达末尾。将其与 toArray 进行对比 - 我们等待 ALL 检索文档并构建 entire 数组。这意味着我们没有从驱动程序和数据库系统协同工作以将结果批处理到您的应用程序这一事实中获得任何优势。批处理旨在提高内存开销和执行时间方面的效率。 如果可以的话,在你的应用程序中利用它。

关于mongodb - 什么是 MongoDB 中的光标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36766956/

相关文章:

c# - 如何更新 mongodb 文档以向数组添加新项目?

MongoDB 聚合 : How do I recombine a date using $project?

java - 如何在java中获取单个MongoDB文档的大小?

mongodb - $lookup 与 php mongodb

SQL游标获取状态含义

python : pymysql error cursor closed when using two databses or multiple databases with cursor

javascript - Mongoose:改进 find() 和 count() 查询

mongodb - 如何更改mongodb数组值的数据类型?

mongodb - 如何在 Mongo 聚合中合并文档中的数组字段

tsql - 在存储过程中使用带有动态 SQL 的游标