public UpdateInfo(ChangeStreamDocument <T> changeStreamDocument) { switch (changeStreamDocument.OperationType) { case ChangeStreamOperationType.Insert: UpdateType = UpdateTypes.Insert; break; case ChangeStreamOperationType.Update: UpdateType = UpdateTypes.Update; break; case ChangeStreamOperationType.Replace: UpdateType = UpdateTypes.Replace; break; case ChangeStreamOperationType.Delete: UpdateType = UpdateTypes.Delete; break; default: UpdateType = UpdateTypes.Undefined; break; } Document = changeStreamDocument.FullDocument; }
static void Main(string[] args) { var noSql = new MFlixNoSqlDbContext( "mongodb+srv://######:########@freecluster-omk9a.mongodb.net/test?retryWrites=true&w=majority", "sample_mflix" ); FilterDefinition <ChangeStreamDocument <Movie> > filterBuilder = Builders <ChangeStreamDocument <Movie> > .Filter .In(x => x.OperationType, new[] { ChangeStreamOperationType.Insert }.ToList()); var options = new ChangeStreamOptions { FullDocument = ChangeStreamFullDocumentOption.UpdateLookup }; PipelineDefinition <ChangeStreamDocument <Movie>, ChangeStreamDocument <Movie> > pipeline = new EmptyPipelineDefinition <ChangeStreamDocument <Movie> >() .Match <ChangeStreamDocument <Movie>, ChangeStreamDocument <Movie> >(filterBuilder); IChangeStreamCursor <ChangeStreamDocument <Movie> > cursor = noSql.GetCollection <Movie>("movies") .Watch(pipeline, options); using (IEnumerator <ChangeStreamDocument <Movie> > enumerator = cursor.ToEnumerable().GetEnumerator()) { while (enumerator.MoveNext()) { ChangeStreamDocument <Movie> doc = enumerator.Current; Console.WriteLine(doc?.DocumentKey); Console.WriteLine(doc?.FullDocument.Title); } } Console.WriteLine("Done!"); }
private void MessageEncountered(ChangeStreamDocument <CompanyDto> document) { OnEmitMessage(new CompanyMessageEventArgs { MessageInfo = $"coming from OnEmitMessage: {document.FullDocument.Id} - {document.FullDocument.Name}", DocumentData = document.FullDocument }); }
public static BaseMongoDbRepository <T> GetSubscribingRepository() { if (CurrentSubscribingRepository == null) { lock (subscriberLockObject) { var currentDocumentType = typeof(T); var currentAssembly = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic) .Single(query => query.FullName == currentDocumentType.Assembly.FullName); foreach (Type exportedType in currentAssembly.GetExportedTypes().Where(query => query.BaseType != null && query.BaseType.UnderlyingSystemType != null && query.BaseType.UnderlyingSystemType.IsGenericType)) { if (exportedType.BaseType.UnderlyingSystemType.GetGenericArguments().FirstOrDefault() == currentDocumentType) { CurrentSubscribingRepository = Activator.CreateInstance(exportedType) as BaseMongoDbRepository <T>; var pipeline = new EmptyPipelineDefinition <ChangeStreamDocument <T> >().Match("{ operationType: /^[^d]/ }"); ChangeStreamOptions options = new ChangeStreamOptions() { FullDocument = ChangeStreamFullDocumentOption.UpdateLookup }; var changeStream = CurrentSubscribingRepository.CurrentCollection.Watch(pipeline, options).ToEnumerable().GetEnumerator(); var task = Task.Run(() => { while (true) { try { changeStream.MoveNext(); ChangeStreamDocument <T> next = changeStream.Current; var currentData = next.FullDocument; if (CurrentSubscribingRepository.SubscriptionTriggered == null) { continue; } var receivers = CurrentSubscribingRepository.SubscriptionTriggered.GetInvocationList(); foreach (SubscriptionTriggeredEventHandler receiver in receivers) { receiver.BeginInvoke(CurrentSubscribingRepository, currentData, null, null); } } catch (Exception ex) { } } }); break; } } } } return(CurrentSubscribingRepository); }
private void AssertChangeStreamDocumentPropertyValuesAgainstBackingDocument(ChangeStreamDocument <BsonDocument> actualDocument) { var backingDocument = actualDocument.BackingDocument; backingDocument.Should().NotBeNull(); var clusterTime = actualDocument.ClusterTime; if (backingDocument.Contains("clusterTime")) { clusterTime.Should().Be(backingDocument["clusterTime"].AsBsonTimestamp); } else { clusterTime.Should().BeNull(); } var collectionNamespace = actualDocument.CollectionNamespace; collectionNamespace.DatabaseNamespace.DatabaseName.Should().Be(backingDocument["ns"]["db"].AsString); collectionNamespace.CollectionName.Should().Be(backingDocument["ns"]["coll"].AsString); var documentKey = actualDocument.DocumentKey; documentKey.Should().Be(backingDocument["documentKey"].AsBsonDocument); var fullDocument = actualDocument.FullDocument; if (backingDocument.Contains("fullDocument")) { fullDocument.Should().Be(backingDocument["fullDocument"].AsBsonDocument); } else { fullDocument.Should().BeNull(); } var operationType = actualDocument.OperationType; operationType.ToString().ToLowerInvariant().Should().Be(backingDocument["operationType"].AsString); var resumeToken = actualDocument.ResumeToken; resumeToken.Should().Be(backingDocument["_id"].AsBsonDocument); var updateDescription = actualDocument.UpdateDescription; if (backingDocument.Contains("updateDescription")) { updateDescription.Should().Be(backingDocument["updateDescription"].AsBsonDocument); } else { updateDescription.Should().BeNull(); } }
/// <summary> /// Generic method for revoking updates by _id /// </summary> /// <param name="deletedEntity"></param> /// <returns></returns> protected Task processNotificableEntityWasDeleted <EntityType>(ChangeStreamDocument <EntityType> deletedEntity) { var deletedEntityId = deletedEntity.DocumentKey["_id"].ToString(); if (deletedEntityId == null) { logger.Fatal($"document without id was received", deletedEntity); return(Task.CompletedTask); } return(updateSenderProxy.revokeNotificationForObject(deletedEntityId)); }
public OperationResult Convert(ChangeStreamDocument <BsonDocument> result) { var document = new BsonDocument { { "operationType", result.OperationType.ToString().ToLowerInvariant() }, { "ns", ConvertNamespace(result.CollectionNamespace) }, { "fullDocument", result.FullDocument } }; return(OperationResult.FromResult(document)); }
private void ProcessEvent(ChangeStreamDocument <EventWrapper> change) { var @event = change.FullDocument; using (var factory = serviceScopeFactory.CreateScope()) { Type handlerGenericType = typeof(IEventHandler <>).MakeGenericType(Type.GetType(@event.EventType)); var service = factory.ServiceProvider.GetRequiredService(handlerGenericType); HandleEvent(service, @event); } }
public OperationResult Convert(ChangeStreamDocument <BsonDocument> result) { var document = new BsonDocument { { "operationType", result.OperationType.ToString().ToLowerInvariant() }, { "ns", ConvertNamespace(result.CollectionNamespace) }, { "fullDocument", () => result.FullDocument, result.FullDocument != null }, { "updateDescription", () => ConvertUpdateDescription(result.UpdateDescription), result.UpdateDescription != null } }; return(OperationResult.FromResult(document)); }
/// <summary> /// Stage A.1: Process entity one /// </summary> /// <param name="newentity"></param> /// <returns></returns> private Task ProcessentityInsert(ChangeStreamDocument <SomeModelOne> newentity) { bool isAdminCompetency = (newentity.FullDocument.positionId == null); if (isAdminCompetency) { return(sendNotificationsToAdmins(newentity.FullDocument)); } else { return(sendNotificationsToPositionsOwners(newentity.FullDocument)); } }
private static string ConvertChangeStreamBsonDocumentToJson(ChangeStreamDocument <BsonDocument> changeStreamDocument) { string json; var subject = new ChangeStreamDocumentSerializer <BsonDocument>(BsonDocumentSerializer.Instance); using (var textWriter = new StringWriter()) using (var writer = new MongoDB.Bson.IO.JsonWriter(textWriter)) { { var context = BsonSerializationContext.CreateRoot(writer); subject.Serialize(context, changeStreamDocument); json = textWriter.ToString(); } } return(json); }
private async Task WatchChange <T>(ChangeStreamDocument <T> arg, CancellationToken cancellationToken) { var input = new TriggeredFunctionData { TriggerValue = arg, }; try { await _contextExecutor.TryExecuteAsync(input, cancellationToken); } catch { // We don't want any function errors to stop the execution // schedule. Errors will be logged to Dashboard already. } }
/// <summary> /// Launch required action depending on performed action (delete/insert/update) /// </summary> /// <param name="entity"></param> /// <returns></returns> private Task Brancher(ChangeStreamDocument <SomeModelOne> entity) { switch (entity.OperationType) { case ChangeStreamOperationType.Delete: return(processNotificableEntityWasDeleted(entity)); case ChangeStreamOperationType.Insert: return(ProcessentityInsert(entity)); case ChangeStreamOperationType.Update: case ChangeStreamOperationType.Replace: return(ProcessentityUpdated(entity)); default: logger.Fatal($"{nameof(entity.OperationType)} is not implemented"); return(Task.CompletedTask); } }
private void AssertChangeStreamDocument(ChangeStreamDocument <BsonDocument> actualDocument, BsonDocument expectedDocument) { JsonDrivenHelper.EnsureAllFieldsAreValid(expectedDocument, "_id", "documentKey", "operationType", "ns", "fullDocument"); AssertChangeStreamDocumentPropertyValuesAgainstBackingDocument(actualDocument); if (expectedDocument.Contains("_id")) { actualDocument.ResumeToken.Should().NotBeNull(); } if (expectedDocument.Contains("documentKey")) { actualDocument.DocumentKey.Should().NotBeNull(); } if (expectedDocument.Contains("operationType")) { var expectedOperationType = (ChangeStreamOperationType)Enum.Parse(typeof(ChangeStreamOperationType), expectedDocument["operationType"].AsString, ignoreCase: true); actualDocument.OperationType.Should().Be(expectedOperationType); } if (expectedDocument.Contains("ns")) { var ns = expectedDocument["ns"].AsBsonDocument; JsonDrivenHelper.EnsureAllFieldsAreValid(ns, "db", "coll"); var expectedDatabaseName = ns["db"].AsString; var expectedCollectionName = ns["coll"].AsString; var expectedCollectionNamespace = new CollectionNamespace(new DatabaseNamespace(expectedDatabaseName), expectedCollectionName); actualDocument.CollectionNamespace.Should().Be(expectedCollectionNamespace); } if (expectedDocument.Contains("fullDocument")) { var actualFullDocument = actualDocument.FullDocument; actualFullDocument.Remove("_id"); var expectedFullDocument = expectedDocument["fullDocument"].AsBsonDocument; actualFullDocument.Should().Be(expectedFullDocument); } }
public static DocumentChange <T> ToDocumentChange <T>(this ChangeStreamDocument <T> change) where T : IMongoDbDocument, new() { if (change.OperationType == ChangeStreamOperationType.Delete) { var oldDevice = new T() { _id = change.DocumentKey["_id"].AsString }; return(new DocumentChange <T>(oldDevice, DocumentChangeKind.Delete)); } var device = change.FullDocument; var changeKind = change.OperationType switch { ChangeStreamOperationType.Insert => DocumentChangeKind.Insert, ChangeStreamOperationType.Update => DocumentChangeKind.Update, ChangeStreamOperationType.Replace => DocumentChangeKind.Replace, _ => throw new InvalidEnumArgumentException($"[BUGCHECK] Unexpected ChangeStreamOperationType ({change.OperationType})."), }; return(new DocumentChange <T>(device, changeKind)); }
public void StartCollectionWatch(MongoClient mongoClient) { var cargoCollection = mongoClient.GetDatabase(APIConstant.LogisticsDatabase) .GetCollection <Models.Cargo>(APIConstant.CargoCollection); var options = new ChangeStreamOptions { FullDocument = ChangeStreamFullDocumentOption.UpdateLookup }; var pipeline = new EmptyPipelineDefinition <ChangeStreamDocument <Cargo> >().Match("{ operationType: { $in: [ 'insert'] } }"); var cursor = cargoCollection.Watch <ChangeStreamDocument <Cargo> >(pipeline, options); var enumerator = cursor.ToEnumerable().GetEnumerator(); while (true) { enumerator.MoveNext(); //var ct = cursor.GetResumeToken(); ChangeStreamDocument <Cargo> doc = enumerator.Current; // Do something here with your document Console.WriteLine(doc.DocumentKey); } }
/// <summary> /// Stage B.1: Branch algo for choosing required notification type /// </summary> /// <param name="updatedentity"></param> /// <returns></returns> private async Task ProcessentityUpdated(ChangeStreamDocument <SomeModelOne> updatedentity) { if (updatedentity.OperationType == ChangeStreamOperationType.Update || updatedentity.OperationType == ChangeStreamOperationType.Replace) { var buildingId = (await somewhatRepositoryOne.getBuildingIdByApartId(updatedentity.FullDocument.apartId)).buildingId; switch (updatedentity.FullDocument.status) { case SomeModelOne.entitiestatus.Rejected: await sendentityRejectedStatus(updatedentity.FullDocument, buildingId); return; case SomeModelOne.entitiestatus.Finished: await sendentityFinishedStatus(updatedentity.FullDocument, buildingId); return; case SomeModelOne.entitiestatus.Assigned: await sendentityInProgress(updatedentity.FullDocument, buildingId, true); await sendentityInProgress(updatedentity.FullDocument, buildingId); return; case SomeModelOne.entitiestatus.Reviewed: case SomeModelOne.entitiestatus.Closed: await sendentityInProgress(updatedentity.FullDocument, buildingId); return; default: logger.Warn($"entity status {nameof(updatedentity.FullDocument.status)} is not supported in `processentityUpdated`"); return; } } }
private void NotifyEntityChangeWatchers(ChangeStreamDocument <BsonDocument> changeStreamDocument) { DocumentChangeObserver.Instance.OnChanged(new DocumentChangeEventArgs(changeStreamDocument)); }
/// <summary> /// This API supports the MongoDb infrastructure and is not intended /// to be used directly from your code. This API may change or be removed in future releases. /// </summary> public DocumentChangeEventArgs(ChangeStreamDocument <BsonDocument> document) { Document = document; }