MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDB :est-il possible de capturer des événements TTL avec Change Stream pour émuler un planificateur (cronjob) ?

J'ai pu utiliser Change Streams et TTL pour émuler un cronjob. J'ai publié un article expliquant ce que j'ai fait en détail et j'ai donné des crédits à :https://www. patreon.com/posts/17697287

Mais, fondamentalement, chaque fois que j'ai besoin de programmer un "événement" pour un document, lorsque je crée le document, je crée également un document d'événement en parallèle. Ce document d'événement aura comme _id le même identifiant que le premier document.

De plus, pour ce document d'événement, je définirai un TTL.

Lorsque le TTL expirera, je capturerai son changement "supprimer" avec Change Streams. Et puis j'utiliserai le documentKey du changement (puisque c'est le même identifiant que le document que je veux déclencher) pour trouver le document cible dans la première collection, et faire ce que je veux avec le document.

J'utilise Node.js avec Express et Mongoose pour accéder à MongoDB. Voici la partie pertinente à ajouter dans 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');
        });
    });

}

Et voici le code pour 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);