OPTIONS
翻译或纠错本页面

创建Tailable游标

概述

默认情况下,当客户端已经耗尽游标中的所有结果的时候,MongoDB将自动关闭这个游标。然而,对于 capped collections ,你可以使用一个 Tailable 游标 ,在客户端耗尽最初游标内的结果后它保持打开状态。tailable 游标在概念上等同于有 -f 选项(也就是 follow 模式)的 tail Unix命令。在客户端插入一个新的额外的文档到一个封顶集合之后,tailable 游标将继续检索文档。

在有着未使用索引的高写入卷的封顶集合上使用tailable游标。例如, replication 使用tailable游标来跟踪主节点的 oplog

注解

如果您的查询是在索引的字段上,不要使用tailable游标,取而代之地,使用一个常规游标。跟踪查询所返回的索引字段的最后一个值。若要检索最新添加的文档,请使用查询条件里索引字段的最后一个值来重新查询,如下例所示:

db.<collection>.find( { indexedField: { $gt: <lastvalue> } } )

考虑 tailable 游标相关的以下行为:

  • tailable 游标不使用索引,并且返回以 natural order 顺序排序的文档。

  • 因为 tailable 游标不使用索引,最初的查询扫描可能是昂贵的;但是,在用完最初的游标之后,随后的最新添加的文档的检索是廉价的。

  • 如果发生下面任何一个,tailable 游标可能会变成 dead ,或者无效的:

    • 该查询返回不匹配。

    • 该游标返回在集合 “end” 的文档,并且然后应用删除这些文档。

    dead 游标有一个 0 id。

查看 driver-specific 方法的 driver documentation 以指定 tailable 游标。更多关于指定一个 tailable 游标细节的信息,请参见 MongoDB wire protocol 文档。

C++ 例子

The tail function uses a tailable cursor to output the results from a query to a capped collection:

  • 该函数通过让查询在一个循环里来处理死了的游标的情况。

  • 为了周期性地检测新数据, cursor->more() 声明也在循环里。

#include "client/dbclient.h"

using namespace mongo;

/*
 * Example of a tailable cursor.
 * The function "tails" the capped collection (ns) and output elements as they are added.
 * The function also handles the possibility of a dead cursor by tracking the field 'insertDate'.
 * New documents are added with increasing values of 'insertDate'.
 */

void tail(DBClientBase& conn, const char *ns) {

    BSONElement lastValue = minKey.firstElement();

    Query query = Query().hint( BSON( "$natural" << 1 ) );

    while ( 1 ) {
        auto_ptr<DBClientCursor> c =
            conn.query(ns, query, 0, 0, 0,
                       QueryOption_CursorTailable | QueryOption_AwaitData );

        while ( 1 ) {
            if ( !c->more() ) {

                if ( c->isDead() ) {
                    break;
                }

                continue;
            }

            BSONObj o = c->next();
            lastValue = o["insertDate"];
            cout << o.toString() << endl;
        }

        query = QUERY( "insertDate" << GT << lastValue ).hint( BSON( "$natural" << 1 ) );
    }
}

The tail function performs the following actions:

  • 初始化 lastValue 变量,这个变量跟踪最后一个访问的值。如果此游标编程 无效的 并且 tail 需要重启查询的时候,这个功能将使用 lastValue 。使用 hint() 以保证这个查询使用 $natural 顺序。

  • 在外 while(1) 循环中,

    • 查询封顶集合并返回一个 tailable 游标,游标阻塞几秒钟以等待新的文档。

      auto_ptr<DBClientCursor> c =
           conn.query(ns, query, 0, 0, 0,
                      QueryOption_CursorTailable | QueryOption_AwaitData );
      
      • 使用 ns 作为该函数的参数来指定封顶的集合。

      • 设置 QueryOption_CursorTailable 选项以创建一个 tailable 游标。

      • 设置 QueryOption_AwaitData 选项让返回的游标阻塞几秒钟以等待数据。

    • 在内 while (1) 循环中,从游标中读取文档:

      • 如果该游标没有更多的文档并且不是无效的,循环内 while 循环重新检查更多的文档。

      • 如果游标没有更多的文档,并且是死的,打断内 while 循环。

      • 如果游标有文档:

        • 输出文档,

        • 更新 lastValue 的值

        • 并且循环内 while (1) 循环以重新检测更多的文档。

    • 如果逻辑打破内 while (1) 循环并且该游标是无效的:

      • 使用 lastValue 值来创建一个新的匹配在 lastValue 之后添加的文档的查询条件。使用 hint() 方法明确地保证 $natural 顺序:

        query = QUERY( "insertDate" << GT << lastValue ).hint( BSON( "$natural" << 1 ) );
        
      • 循环外部 while (1) 循环以使用新的查询条件重新查询,并且重复循环。