i'm trying to use mongodb as a network wide configuration storage. This the same app runs on multiple machines on the network, each pulls its configuration from its local mongodb. The
mongodbs are synced. What i would like is to get a callback/notification in all n-1 apps if one application changes any of the config values.
Is this kind of setup possible ?
(It would save me from doing the network transfer/syncronisation etc. myself.)
MongoDB doesn’t yet have triggers, but you can hook your application to tail off the oplog collection and do something every time a document is deleted (or updated, or inserted, etc.)
The 3 part blog post here might be helpful on how to do this :
http://www.kchodorow.com/blog/2010/10/12/replication-internals/
What do you mean that the mongodbs are synched? Are they actually replicating data amongst themselves? I assume not since it sounds as though you want to manage that synching.
In the past, I've accomplished something similar with MongoDB and asp which requires a centralized mongo instance (replica pair, etc). Basically, every time a change is made to the local instance, a capped collection on the central instance is also updated with the new version of the config value and a timestamp of when that value was last updated and which server updated the value.
A separate thread is then run on the individual servers which keeps a tailable cursor open against the central instance. Whenever a new record is retrieved by the cursor, new values are compared against the timestamp of the local instance and updated accordingly (or not). Must be careful when comparing those timestamp and the "authoritative" server that made the change to insure that you don't wind up with an update storm. You also need to be aware of whether the update is because somebody actually changed the value or whether its because the value was "replicated" - you don't want to update the central instance if the update is a replication update.
As of mongodb 3.6, you can now hook actions to the change stream. This gives you a tailable cursor which you can use to listen to changes (e.g. crud operations) on a particular collection.
The change stream is built on top of the oplog and is accessible for anything that is using the oplog.
Change streams are resumable and also can be used with aggregation operators such as $match, $project...
More info here (Java example):
http://mongodb.github.io/mongo-java-driver/3.6/driver/tutorials/change-streams/
And here is the snippet from https://www.mongodb.com/mongodb-3.6 (Java):
// 1. The database for reactive, real-time applications
MongoClient mongoClient;
// Create a new MongoClient with a MongoDB URI string.
if (args.length == 0) {
// Defaults to a localhost replicaset on ports: 27017, 27018, 27019
mongoClient = new MongoClient(new
MongoClientURI("mongodb://localhost:27017,localhost:27018,localhost:27019"));
} else {
mongoClient = new MongoClient(new MongoClientURI(args[0]));
}
// Select the MongoDB database.
MongoDatabase database = mongoClient.getDatabase("testChangeStreams");
database.drop();
sleep();
// Select the collection to query.
MongoCollection<Document> collection = database.getCollection("documents");
// Create the change stream cursor.
MongoCursor<Document> cursor = collection.watch().iterator();
If you are working in C#, examples can be found here:
var inventory = database.GetCollection<BsonDocument>("inventory");
var document = new BsonDocument("x", 1);
inventory.InsertOne(document);
new Thread(() =>
{
Thread.Sleep(TimeSpan.FromMilliseconds(100));
var filter = new BsonDocument("_id", document["_id"]);
var update = "{ $set : { x : 2 } }";
inventory.UpdateOne(filter, update);
})
.Start();
// Start Changestream Example 2
var options = new ChangeStreamOptions { FullDocument = ChangeStreamFullDocumentOption.UpdateLookup };
var enumerator = inventory.Watch(options).ToEnumerable().GetEnumerator();
enumerator.MoveNext();
var next = enumerator.Current;
enumerator.Dispose();
// End Changestream Example 2
var expectedFullDocument = document.Set("x", 2);
next.FullDocument.Should().Be(expectedFullDocument);