我正在用MongoDB作为数据存储创建一种后台作业队列系统。在生成工人处理作业之前,我如何“监听”MongoDB集合的插入?

是否需要每隔几秒钟轮询一次,以查看与上次相比是否有任何更改,或者是否有一种方法可以让脚本等待插入的发生?

这是一个PHP项目,我正在工作,但请随意回答在Ruby或语言不可知。


当前回答

许多这些答案只会给你新的记录,而不是更新和/或非常低效

要做到这一点,唯一可靠、高效的方法是在本地db: oplog上创建一个可尾游标。rs集合得到所有的变化到MongoDB和做什么,你会。(MongoDB甚至在内部或多或少地支持复制!)

oplog包含内容的解释: https://www.compose.com/articles/the-mongodb-oplog-and-node-js/

一个Node.js库的例子,它提供了一个关于oplog可以做什么的API: https://github.com/cayasso/mongo-oplog

其他回答

或者,你可以使用标准的Mongo findupdate方法,在回调中,在回调运行时触发EventEmitter事件(在Node中)。

应用程序或体系结构中侦听此事件的任何其他部分都将收到更新通知,并将任何相关数据发送到那里。这是实现Mongo通知的一个非常简单的方法。

自从MongoDB 3.6以来,会有一个新的通知API叫做Change Streams,你可以使用它。有关示例,请参阅这篇博客文章。例子如下:

cursor = client.my_db.my_collection.changes([
    {'$match': {
        'operationType': {'$in': ['insert', 'replace']}
    }},
    {'$match': {
        'newDocument.n': {'$gte': 1}
    }}
])

# Loops forever.
for change in cursor:
    print(change['newDocument'])

有一套很棒的服务叫做MongoDB Stitch。查看stitch函数/触发器。注意,这是一个基于云的付费服务(AWS)。在您的例子中,对于插入,您可以调用用javascript编写的自定义函数。

这里有一个工作的java示例。

 MongoClient mongoClient = new MongoClient();
    DBCollection coll = mongoClient.getDatabase("local").getCollection("oplog.rs");

    DBCursor cur = coll.find().sort(BasicDBObjectBuilder.start("$natural", 1).get())
            .addOption(Bytes.QUERYOPTION_TAILABLE | Bytes.QUERYOPTION_AWAITDATA);

    System.out.println("== open cursor ==");

    Runnable task = () -> {
        System.out.println("\tWaiting for events");
        while (cur.hasNext()) {
            DBObject obj = cur.next();
            System.out.println( obj );

        }
    };
    new Thread(task).start();

键是这里给出的QUERY OPTIONS。

你也可以改变查找查询,如果你不需要每次都加载所有的数据。

BasicDBObject query= new BasicDBObject();
query.put("ts", new BasicDBObject("$gt", new BsonTimestamp(1471952088, 1))); //timestamp is within some range
query.put("op", "i"); //Only insert operation

DBCursor cur = coll.find(query).sort(BasicDBObjectBuilder.start("$natural", 1).get())
.addOption(Bytes.QUERYOPTION_TAILABLE | Bytes.QUERYOPTION_AWAITDATA);

看看这个:改变流

2018年1月10日——3.6版

*编辑:我写了一篇关于如何做到这一点的文章https://medium.com/riow/mongodb-data-collection-change-85b63d96ff76

https://docs.mongodb.com/v3.6/changeStreams/


这是mongodb 3.6中的新功能 https://docs.mongodb.com/manual/release-notes/3.6/ 2018/01/10

$ mongod --version
db version v3.6.2

为了使用changeStreams,数据库必须是一个复制集

关于复制集的更多信息: https://docs.mongodb.com/manual/replication/

默认情况下,数据库将是“独立的”。

如何将一个独立的副本集:https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/


下面的示例是一个实际应用程序,说明如何使用它。 *特别针对Node。

/* file.js */
'use strict'


module.exports = function (
    app,
    io,
    User // Collection Name
) {
    // SET WATCH ON COLLECTION 
    const changeStream = User.watch();  

    // Socket Connection  
    io.on('connection', function (socket) {
        console.log('Connection!');

        // USERS - Change
        changeStream.on('change', function(change) {
            console.log('COLLECTION CHANGED');

            User.find({}, (err, data) => {
                if (err) throw err;

                if (data) {
                    // RESEND ALL USERS
                    socket.emit('users', data);
                }
            });
        });
    });
};
/* END - file.js */

有用的链接: https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set https://docs.mongodb.com/manual/tutorial/change-streams-example

https://docs.mongodb.com/v3.6/tutorial/change-streams-example http://plusnconsulting.com/post/MongoDB-Change-Streams