MongoDB:是否可以使用Change Stream捕获TTL事件以模拟调度程序(cronjob)? [英] MongoDB: is it possible to capture TTL events with Change Stream to emulate a scheduler (cronjob)?

查看:268
本文介绍了MongoDB:是否可以使用Change Stream捕获TTL事件以模拟调度程序(cronjob)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是MongoDB的新手,我正在寻找一种执行以下操作的方法:

I'm new to MongoDB and I'm looking for a way to do the following:

我有一些可用的事物"的集合. 用户可以保存"事物"并减少可用事物的数量. 但是他有时间在它过期之前使用它. 如果过期,则必须将其返回到集合中,然后再次递增.

I have a collection of a number of available "things" to be used. The user can "save" a "thing" and decrement the number of available things. But he has a time to use it before it expires. If it expires, the thing has to go back to the collection, incrementing it again.

如果有一种方法可以监视Mongo中的到期日期",那将是理想的.但是在搜索中,我只发现了TTL(生存时间),可以自动删除整个文档.

It would be ideal if there was a way to monitor "expiring dates" in Mongo. But in my searches I've only found a TTL (time to live) for automatically deleting entire documents.

但是,我需要的是到期的事件" ...比我想知道是否可以使用Change Streams捕获此事件.然后,我可以使用该事件再次增加事物".

However, what I need is the "event" of the expiration... Than I was wondering if it would be possible to capture this event with Change Streams. Then I could use the event to increment "things" again.

有可能吗?还是会有一种更好的方式来做我想做的事?

Is it possible or not? Or would there be a better way of doing what I want?

推荐答案

我能够使用更改流和TTL来模拟cronjob.我发表了一篇文章,详细解释了我的所作所为,并在以下位置给予了赞扬: https://www.patreon.com/posts/17697287

I was able to use Change Streams and TTL to emulate a cronjob. I've published a post explaining what I did in details and gave credits at: https://www.patreon.com/posts/17697287

但是,基本上,每当我需要为文档安排事件"时,在创建文档时,我也会并行创建一个事件文档.此事件文档的_id与第一个文档的ID相同.

But, basically, anytime I need to schedule an "event" for a document, when I'm creating the document I also create an event document in parallel. This event document will have as its _id the same id of the first document.

此外,对于此事件文档,我将设置一个TTL.

Also, for this event document I will set a TTL.

当TTL过期时,我将使用Change Streams捕获其删除"更改.然后,我将使用更改的documentKey(因为它与我要触发的文档具有相同的ID)来在第一个集合中查找目标文档,并对文档进行任何操作.

When the TTL expires I will capture its "delete" change with Change Streams. And then I'll use the documentKey of the change (since it's the same id as the document I want to trigger) to find the target document in the first collection, and do anything I want with the document.

我正在使用带有Express和Mongoose的Node.js来访问MongoDB. 这是要添加到App.js中的相关部分:

I'm using Node.js with Express and Mongoose to access MongoDB. Here is the relevant part to be added in the App.js:

const { ReplSet } = require('mongodb-topology-manager');

run().catch(error => console.error(error));

async function run() {
    console.log(new Date(), 'start');
    const bind_ip = 'localhost';
    // Starts a 3-node replica set on ports 31000, 31001, 31002, replica set
    // name is "rs0".
    const replSet = new ReplSet('mongod', [
        { options: { port: 31000, dbpath: `${__dirname}/data/db/31000`, bind_ip } },
        { options: { port: 31001, dbpath: `${__dirname}/data/db/31001`, bind_ip } },
        { options: { port: 31002, dbpath: `${__dirname}/data/db/31002`, bind_ip } }
    ], { replSet: 'rs0' });

    // Initialize the replica set
    await replSet.purge();
    await replSet.start();
    console.log(new Date(), 'Replica set started...');

    // Connect to the replica set
    const uri = 'mongodb://localhost:31000,localhost:31001,localhost:31002/' + 'test?replicaSet=rs0';
    await mongoose.connect(uri);
    var db = mongoose.connection;
    db.on('error', console.error.bind(console, 'connection error:'));
    db.once('open', function () {
        console.log("Connected correctly to server");
    });

    // To work around "MongoError: cannot open $changeStream for non-existent database: test" for this example
    await mongoose.connection.createCollection('test');

    // *** we will add our scheduler here *** //

    var Item = require('./models/item');
    var ItemExpiredEvent = require('./models/scheduledWithin');

    let deleteOps = {
      $match: {
          operationType: "delete" 
      }
    };

    ItemExpiredEvent.watch([deleteOps]).
        on('change', data => {
            // *** treat the event here *** //
            console.log(new Date(), data.documentKey);
            Item.findById(data.documentKey, function(err, item) {
                console.log(item);
            });
        });

    // The TTL set in ItemExpiredEvent will trigger the change stream handler above
    console.log(new Date(), 'Inserting item');
    Item.create({foo:"foo", bar: "bar"}, function(err, cupom) {
        ItemExpiredEvent.create({_id : item._id}, function(err, event) {
            if (err) console.log("error: " + err);
            console.log('event inserted');
        });
    });

}

这是model/ScheduledWithin的代码:

And here is the code for model/ScheduledWithin:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var ScheduledWithin = new Schema({
    _id: mongoose.Schema.Types.ObjectId,
}, {timestamps: true}); 
// timestamps: true will automatically create a "createdAt" Date field

ScheduledWithin.index({createdAt: 1}, {expireAfterSeconds: 90});

module.exports = mongoose.model('ScheduledWithin', ScheduledWithin);

这篇关于MongoDB:是否可以使用Change Stream捕获TTL事件以模拟调度程序(cronjob)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆