Currently, I have a use case as follows:
- Capture all events that occur to data within the collection
- Identify the fields that have been updated
- Create audit events that are app specific for the fields that have been updated.
For ex, if an item has a field called “Status” and it changes from “Write” to “Review”, I should capture this in the Change Stream and then create a log called “Status Change” and persist it in a different collection.
Currently, this is the code I’ve written:
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using TodoApp.Configurations;
namespace TodoApp.Background
{
public class Service : IHostedService
{
private readonly IMongoCollection<BsonDocument> _mongoCollection;
private IChangeStreamCursor<BsonDocument> _changeStreamCursor;
private Task _watchTask;
private CancellationTokenSource _cancellationTokenSource;
public Service(IMongoClient mongoClient, IOptions<Database> options)
{
var database = mongoClient.GetDatabase(options.Value.DatabaseName);
_mongoCollection = database.GetCollection<BsonDocument>(options.Value.CollectionName);
}
public Task StartAsync(CancellationToken cancellationToken)
{
_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_watchTask = Task.Run(() => WatchForChangesAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
return Task.CompletedTask;
}
private async Task WatchForChangesAsync(CancellationToken cancellationToken)
{
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<BsonDocument>>()
.Match(change =>
change.OperationType == ChangeStreamOperationType.Insert ||
change.OperationType == ChangeStreamOperationType.Update ||
change.OperationType == ChangeStreamOperationType.Replace
)
.AppendStage<ChangeStreamDocument<BsonDocument>, ChangeStreamDocument<BsonDocument>, BsonDocument>(
@"{
$project: {
'_id': 1,
'fullDocument': 1,
'ns': 1,
'documentKey': 1
}
}"
);
ChangeStreamOptions options = new()
{
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup
};
_changeStreamCursor = _mongoCollection.Watch(
pipeline,
options
);
Console.WriteLine("Watching for changes...");
while (await _changeStreamCursor.MoveNextAsync(cancellationToken))
{
var batch = _changeStreamCursor.Current;
foreach (var change in batch)
{
// var serializedChange = change.ToJson();
// var document = BsonSerializer.Deserialize<Domain.ChangeStream<BsonDocument>>(serializedChange);
Console.WriteLine(change);
// Process the change
}
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_cancellationTokenSource.Cancel();
return Task.WhenAny(_watchTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
}
}
The events were perfectly working with Update Description on MongoDB Cloud, but when I switched it to Azure Cosmos it didn’t support it. Are there any alternatives for this?