Para agentes de IA: hay un índice de documentación disponible en https://www.mongodb.com/es/docs/llms.txt — versiones en markdown de todas las páginas están disponibles agregando .md a cualquier ruta URL.
Docs Menu

Supervisar los cambios en los datos

En esta guía, puedes aprender a usar un flujo de cambios para supervisar los cambios en tiempo real de tus datos. Un flujo de cambios es una funcionalidad de MongoDB Server que permite que la aplicación se suscriba a cambios en los datos de una colección, base de datos o implementación.

Tip

Atlas Stream Processing

Como alternativa a los flujos de cambios, puedes usar Atlas Stream Processing para procesar y transformar flujos de datos. A diferencia de los flujos de cambios, que solo registran eventos de base de datos, Atlas Stream Processing administra múltiples tipos de eventos de datos y ofrece capacidades avanzadas de procesamiento de datos. Para obtener más información sobre esta funcionalidad, consulta Atlas Stream Processing en la documentación de MongoDB Atlas.

Los ejemplos en esta guía utilizan la colección sample_restaurants.restaurants de los conjuntos de datos de muestra de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de muestra, consulte Introducción al driver .NET/C#.

En los ejemplos de esta página se utilizan las siguientes clases Restaurant, Address y GradeEntry como modelos:

public class Restaurant
{
public ObjectId Id { get; set; }
public string Name { get; set; }
[BsonElement("restaurant_id")]
public string RestaurantId { get; set; }
public string Cuisine { get; set; }
public Address Address { get; set; }
public string Borough { get; set; }
public List<GradeEntry> Grades { get; set; }
}
public class Address
{
public string Building { get; set; }
[BsonElement("coord")]
public double[] Coordinates { get; set; }
public string Street { get; set; }
[BsonElement("zipcode")]
public string ZipCode { get; set; }
}
public class GradeEntry
{
public DateTime Date { get; set; }
public string Grade { get; set; }
public float? Score { get; set; }
}

Nota

Los documentos de la colección restaurants utilizan la convención de nomenclatura snake-case. Los ejemplos de esta guía utilizan un ConventionPack para deserializar los campos de la colección en notación Pascal y asignarlos a las propiedades de la clase Restaurant.

Para aprender más sobre la serialización personalizada, consultar Serialización personalizada.

Para abrir un flujo de cambios, llama al método Watch() o WatchAsync(). La instancia en la que llama al método determina el alcance de los eventos a los que escucha el flujo de cambios. Puede llamar a los métodos Watch() o WatchAsync() en las siguientes clases:

  • MongoClient: Para supervisar todos los cambios en la implementación de MongoDB

  • Database: Para supervisar los cambios en todas las colecciones de la base de datos

  • Collection: Para supervisar los cambios en la colección

El siguiente ejemplo abre un flujo de cambios en la colección restaurants y muestra los cambios a medida que ocurren. Selecciona la pestaña Synchronous o Asynchronous para ver el código correspondiente.

var database = client.GetDatabase("sample_restaurants");
var collection = database.GetCollection<Restaurant>("restaurants");
// Opens a change stream and prints the changes as they're received
using (var cursor = collection.Watch())
{
foreach (var change in cursor.ToEnumerable())
{
Console.WriteLine("Received the following type of change: " + change.BackingDocument);
}
}
var database = client.GetDatabase("sample_restaurants");
var collection = database.GetCollection<Restaurant>("restaurants");
// Opens a change streams and print the changes as they're received
using var cursor = await collection.WatchAsync();
await cursor.ForEachAsync(change =>
{
Console.WriteLine("Received the following type of change: " + change.BackingDocument);
});

Para comenzar a observar los cambios, ejecuta la aplicación. Luego, en una aplicación o shell aparte, modifica la colección restaurants. Actualizar un documento que tiene un "name" valor de "Blarney Castle" produce la siguiente salida de flujo de cambios:

{ "_id" : { "_data" : "..." }, "operationType" : "update", "clusterTime" : Timestamp(...),
"wallTime" : ISODate("..."), "ns" : { "db" : "sample_restaurants", "coll" : "restaurants" },
"documentKey" : { "_id" : ObjectId("...") }, "updateDescription" : { "updatedFields" : { "cuisine" : "Irish" },
"removedFields" : [], "truncatedArrays" : [] } }

Puede pasar el parámetro pipeline a los métodos Watch() y WatchAsync() para modificar la salida del flujo de cambios. Este parámetro te permite monitorear solo los eventos de cambio especificados. Creá el pipeline usando la clase EmptyPipelineDefinition y añadiendo los métodos de etapa de agregación correspondientes.

Puedes especificar las siguientes etapas de agregación en el parámetro pipeline:

  • $addFields

  • $changeStreamSplitLargeEvent

  • $match

  • $project

  • $replaceRoot

  • $replaceWith

  • $redact

  • $set

  • $unset

Tip

Para aprender cómo construir un pipeline de agregación usando la clase PipelineDefinitionBuilder, consulta Etapas del pipeline de agregación en la guía de Operaciones con Builders.

Para obtener más información sobre cómo modificar la salida de tu flujo de cambios, consulta la sección Modificar salida del flujo de cambio en el manual del MongoDB Server.

El siguiente ejemplo utiliza el parámetro pipeline para abrir un flujo de cambios que registre solo las operaciones de actualización. Selecciona la pestaña Synchronous o Asynchronous para ver el código correspondiente.

var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<Restaurant>>()
.Match(change => change.OperationType == ChangeStreamOperationType.Update);
// Opens a change streams and print the changes as they're received
using (var cursor = collection.Watch(pipeline))
{
foreach (var change in cursor.ToEnumerable())
{
Console.WriteLine("Received the following change: " + change);
}
}
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<Restaurant>>()
.Match(change => change.OperationType == ChangeStreamOperationType.Update);
// Opens a change stream and prints the changes as they're received
using (var cursor = await collection.WatchAsync(pipeline))
{
await cursor.ForEachAsync(change =>
{
Console.WriteLine("Received the following change: " + change);
});
}

Si la aplicación genera eventos de cambio que superan los 16 MB de tamaño, el servidor devuelve un error BSONObjectTooLarge. Para evitar este error, puedes usar la etapa $changeStreamSplitLargeEvent pipeline para dividir los eventos en fragmentos más pequeños. La API de agregación del driver .NET/C# incluye el método ChangeStreamSplitLargeEvent(), que puedes usar para añadir la etapa $changeStreamSplitLargeEvent a la pipeline de flujo de cambios.

Este ejemplo instruye al driver a observar los cambios y dividir los eventos de cambio que superen el límite de 16 MB. El código imprime el documento de cambio para cada evento y llama a métodos asistentes para reensamblar cualquier fragmento de evento:

var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<Restaurant>>()
.ChangeStreamSplitLargeEvent();
using var cursor = collection.Watch(pipeline);
foreach (var completeEvent in GetNextChangeStreamEvent(cursor.ToEnumerable().GetEnumerator()))
{
Console.WriteLine("Received the following change: " + completeEvent.BackingDocument);
}
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<Restaurant>>()
.ChangeStreamSplitLargeEvent();
using var cursor = await collection.WatchAsync(pipeline);
await foreach (var completeEvent in GetNextChangeStreamEventAsync(cursor))
{
Console.WriteLine("Received the following change: " + completeEvent.BackingDocument);
}

Nota

Recomendamos volver a ensamblar los fragmentos de eventos de cambios, como se muestra en el ejemplo anterior, pero este paso es opcional. Puede usar la misma lógica para observar tanto los eventos de cambio de división como los completos.

El ejemplo anterior utiliza los métodos GetNextChangeStreamEvent(), GetNextChangeStreamEventAsync() y MergeFragment() para reagrupar los fragmentos de eventos de cambio en un único documento de flujo de cambios. El siguiente código define estos métodos:

// Fetches the next complete change stream event
private static IEnumerable<ChangeStreamDocument<TDocument>> GetNextChangeStreamEvent<TDocument>(
IEnumerator<ChangeStreamDocument<TDocument>> changeStreamEnumerator)
{
while (changeStreamEnumerator.MoveNext())
{
var changeStreamEvent = changeStreamEnumerator.Current;
if (changeStreamEvent.SplitEvent != null)
{
var fragment = changeStreamEvent;
while (fragment.SplitEvent.Fragment < fragment.SplitEvent.Of)
{
changeStreamEnumerator.MoveNext();
fragment = changeStreamEnumerator.Current;
MergeFragment(changeStreamEvent, fragment);
}
}
yield return changeStreamEvent;
}
}
// Merges a fragment into the base event
private static void MergeFragment<TDocument>(
ChangeStreamDocument<TDocument> changeStreamEvent,
ChangeStreamDocument<TDocument> fragment)
{
foreach (var element in fragment.BackingDocument)
{
if (element.Name != "_id" && element.Name != "splitEvent")
{
changeStreamEvent.BackingDocument[element.Name] = element.Value;
}
}
}
// Fetches the next complete change stream event
private static async IAsyncEnumerable<ChangeStreamDocument<TDocument>> GetNextChangeStreamEventAsync<TDocument>(
IAsyncCursor<ChangeStreamDocument<TDocument>> changeStreamCursor)
{
var changeStreamEnumerator = GetNextChangeStreamEventFragmentAsync(changeStreamCursor).GetAsyncEnumerator();
while (await changeStreamEnumerator.MoveNextAsync())
{
var changeStreamEvent = changeStreamEnumerator.Current;
if (changeStreamEvent.SplitEvent != null)
{
var fragment = changeStreamEvent;
while (fragment.SplitEvent.Fragment < fragment.SplitEvent.Of)
{
await changeStreamEnumerator.MoveNextAsync();
fragment = changeStreamEnumerator.Current;
MergeFragment(changeStreamEvent, fragment);
}
}
yield return changeStreamEvent;
}
}
private static async IAsyncEnumerable<ChangeStreamDocument<TDocument>> GetNextChangeStreamEventFragmentAsync<TDocument>(
IAsyncCursor<ChangeStreamDocument<TDocument>> changeStreamCursor)
{
while (await changeStreamCursor.MoveNextAsync())
{
foreach (var changeStreamEvent in changeStreamCursor.Current)
{
yield return changeStreamEvent;
}
}
}
// Merges a fragment into the base event
private static void MergeFragment<TDocument>(
ChangeStreamDocument<TDocument> changeStreamEvent,
ChangeStreamDocument<TDocument> fragment)
{
foreach (var element in fragment.BackingDocument)
{
if (element.Name != "_id" && element.Name != "splitEvent")
{
changeStreamEvent.BackingDocument[element.Name] = element.Value;
}
}
}

Tip

Para aprender más sobre cómo dividir eventos de cambio grandes, consulte $changeStreamSplitLargeEvent en el manual de MongoDB Server.

Los métodos Watch() y WatchAsync() aceptan parámetros opcionales, que representan opciones que puedes usar para configurar la operación. Si no se especifican opciones, el driver no personaliza la operación.

La siguiente tabla describe las opciones que puedes configurar para personalizar el comportamiento de Watch() y WatchAsync():

Opción
Descripción

FullDocument

Especifica si se debe mostrar el documento completo después del cambio, en lugar de mostrar solo los cambios realizados en el documento. Para aprender más sobre esta opción, consulta Incluir preimágenes y posimágenes.

FullDocumentBeforeChange

Especifica si se debe mostrar el documento completo tal como estaba antes del cambio, en lugar de mostrar solo las modificaciones realizadas en el documento. Para obtener más información sobre esta opción, consulte Incluir imágenes previas y posteriores.

ResumeAfter

Indica a Watch() o WatchAsync() que reanude la devolución de cambios después de la operación especificada en el token de reanudación.
Cada documento de evento de flujo de cambios incluye un token de reanudación como el campo _id. Pase todo el campo _id del documento de evento de cambio que representa la operación que desea reanudar después.
ResumeAfter es mutuamente excluyente con StartAfter y StartAtOperationTime.

StartAfter

Indica a Watch() o WatchAsync() que inicie un nuevo flujo de cambios después de la operación especificada en el token de reanudación. Permite que las notificaciones se reanuden después de un evento de invalidación.
Cada documento de evento de flujo de cambios incluye un token de reanudación como el campo _id. Pase todo el campo _id del documento de evento de cambio que representa la operación que desea reanudar después.
StartAfter es mutuamente excluyente con ResumeAfter y StartAtOperationTime.

StartAtOperationTime

Dirige Watch() o WatchAsync() para que devuelva solo los eventos que se producen después de la marca de tiempo especificada.
StartAtOperationTime es mutuamente excluyente con ResumeAfter y StartAfter.

MaxAwaitTime

Especifica el tiempo máximo, en milisegundos, que el servidor espera para reportar nuevos cambios de datos al cursor del flujo de cambios antes de devolver un grupo vacío. Por defecto 1000 milisegundos.

ShowExpandedEvents

A partir de MongoDB Server v6.0, los flujos de cambios admiten notificaciones de cambios para eventos de Data Definition lenguaje (DDL), como los eventos createIndexes y dropIndexes). Para incluir eventos ampliados en un flujo de cambios, crea el cursor del flujo de cambios y configura este parámetro en True.

batchSize

Especifica el número máximo de documentos que un flujo de cambios puede devolver en cada agrupar, lo que se aplica a Watch() o WatchAsync(). Si la opción batchSize no está configurada, las funciones de supervisión tienen un tamaño de agrupamiento inicial de 101 documentos y un tamaño máximo de 16 mebibytes (MiB) para cada agrupamiento posterior. Esta opción puede aplicar un límite inferior a 16 MiB, pero no uno mayor. Si configura batchSize en un límite que da como resultado agrupamientos mayores que 16 MiB, esta opción no tiene ningún efecto y Watch() o WatchAsync() utiliza el tamaño de agrupamiento por defecto.

Collation

Especifica la intercalación que se utilizará para el cursor del flujo de cambios. Consulte la sección Intercalación de esta página para obtener más información.

Comment

Adjunta un comentario a la operación.

Para configurar la intercalación para tu operación, crea una instancia de la clase intercalación.

La siguiente tabla describe los parámetros que acepta el constructor Collation. También enumera la propiedad de clase correspondiente que se puede usar para leer el valor de cada configuración.

Parameter
Descripción
Propiedad de clase

locale

Especifica la localización de los componentes internacionales para Unicode (ICU). Para obtener una lista de las configuraciones regionales admitidas, consulte Configuraciones regionales de intercalación y parámetros predeterminados en el manual de MongoDB Server.

Si desea utilizar una comparación binaria simple, utilice la propiedad estática Collation.Simple para devolver un objeto Collation con la configuración regional locale establecida en "simple".
Tipo de dato: string

Locale

caseLevel

(Opcional) Especifica si se debe incluir la comparación de mayúsculas y minúsculas.

Cuando este argumento es true, el comportamiento del driver depende del valor del argumento strength:

- Si strength es CollationStrength.Primary, el driver compara los caracteres base y las mayúsculas y minúsculas.
- Si strength es CollationStrength.Secondary, el driver compara los caracteres base, los diacríticos, otras diferencias secundarias y las mayúsculas y minúsculas.
- Si strength es cualquier otro valor, este argumento se ignora.

Cuando este argumento es false, el driver no incluye la comparación de mayúsculas y minúsculas en el nivel de fuerza Primary o Secondary.

Tipo de dato: boolean
Por defecto: false

CaseLevel

caseFirst

(Opcional) Especifica el orden de clasificación de las diferencias de mayúsculas y minúsculas durante las comparaciones de nivel terciario.

tipo de dato: CollationCaseFirst
por defecto: CollationCaseFirst.Off

CaseFirst

strength

(Opcional) Especifica el nivel de comparación que se debe realizar, tal como se define en la documentación de ICU.

Tipo de dato: CollationStrength
Por defecto: CollationStrength.Tertiary

Strength

numericOrdering

(Opcional) Especifica si el driver compara las strings numéricas como números.

Si este argumento es true, el driver compara las cadenas numéricas como números. Por ejemplo, al comparar las cadenas "10" y "2", el driver trata los valores como 10 y 2, y encuentra que 10 es mayor.

Si este argumento es false o está excluido, el driver compara las cadenas numéricas como cadenas. Por ejemplo, al comparar las cadenas "10" y "2", el driver compara un carácter a la vez. Debido a que "1" es menor que "2", el driver encuentra que "10" es menor que "2".

Para obtener más información, consulte Restricciones de intercalación en el manual de MongoDB Server.

Tipo de dato: boolean
Por defecto: false

NumericOrdering

alternate

(Opcional) Especifica si el driver considera los espacios en blanco y la puntuación como caracteres base a efectos de comparación.

Tipo de dato: CollationAlternate
Por defecto: CollationAlternate.NonIgnorable (los espacios y la puntuación se consideran caracteres base)

Alternate

maxVariable

(Opcional) Especifica qué caracteres considera el controlador como ignorables cuando el alternate argumento CollationAlternate.Shifted es.

Tipo de datos: CollationMaxVariable
Valor predeterminado: CollationMaxVariable.Punctuation (el controlador ignora la puntuación y los espacios)

MaxVariable

normalization

(Opcional) Especifica si el controlador normaliza el texto según sea necesario.

La mayoría del texto no requiere normalización. Para obtener más información sobre la normalización, consulte la documentación de ICU.

Tipo de datos: boolean
Predeterminado: false

Normalization

backwards

(Opcional) Especifica si las strings que contienen diacríticos se ordenan de atrás hacia adelante en la string.

Tipo de dato: boolean
Por defecto: false

Backwards

Más información sobre la intercalación en la página Intercalación en el manual de MongoDB Server.

Importante

Puede habilitar pre imágenes y post imágenes en colecciones solo si su implementación utiliza MongoDB v6.0 o posterior.

De forma predeterminada, cuando realizas una operación en una colección, el evento de cambio correspondiente solo incluye el delta de los campos modificados por esa operación. Para ver el documento completo antes o después de un cambio, cree un objeto ChangeStreamOptions y especifique las opciones FullDocumentBeforeChange o FullDocument. Luego, pasa el objeto ChangeStreamOptions al método Watch() o WatchAsync().

La preimagen es la versión completa de un documento antes de un cambio. Para incluir la preimagen en el evento de flujo de cambios, se debe establecer la opción FullDocumentBeforeChange en uno de los siguientes valores:

  • ChangeStreamFullDocumentBeforeChangeOption.WhenAvailable: El evento de cambio incluye una preimagen del documento modificado para los eventos de cambio solo si la preimagen está disponible.

  • ChangeStreamFullDocumentBeforeChangeOption.RequiredEl evento de cambio incluye una preimagen del documento modificado para los eventos de cambio. Si la preimagen no está disponible, el driver genera un error.

La post-imagen es la versión completa de un documento después de un cambio. Para incluir la post-imagen en el evento del flujo de cambios, configure la opción FullDocument en uno de los siguientes valores:

  • ChangeStreamFullDocumentOption.UpdateLookup: El evento de cambio incluye una copia de todo el documento cambiado a partir de cierto tiempo después del cambio.

  • ChangeStreamFullDocumentOption.WhenAvailable: El evento de cambio incluye una postimagen del documento modificado para eventos de cambio solo si la postimagen está disponible.

  • ChangeStreamFullDocumentOption.Required: El evento de cambio incluye una imagen posterior del documento modificado para eventos de cambio. Si la imagen posterior no está disponible, el driver genera un error.

El siguiente ejemplo abre un flujo de cambios en una colección e incluye la posimagen de los documentos actualizados al especificar la opción FullDocument. Selecciona la pestaña Synchronous o Asynchronous para ver el código correspondiente.

var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<Restaurant>>()
.Match(change => change.OperationType == ChangeStreamOperationType.Update);
var options = new ChangeStreamOptions
{
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup,
};
using (var cursor = collection.Watch(pipeline, options))
{
foreach (var change in cursor.ToEnumerable())
{
Console.WriteLine(change.FullDocument.ToBsonDocument());
}
}
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<Restaurant>>()
.Match(change => change.OperationType == ChangeStreamOperationType.Update);
var options = new ChangeStreamOptions
{
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup,
};
using var cursor = await collection.WatchAsync(pipeline, options);
await cursor.ForEachAsync(change =>
{
Console.WriteLine(change.FullDocument.ToBsonDocument());
});

Ejecutar el ejemplo de código anterior y actualizar un documento que tenga un valor de "name" igual a "Blarney Castle" resulta en la siguiente salida del flujo de cambios:

{ "_id" : ObjectId("..."), "name" : "Blarney Castle", "restaurant_id" : "40366356",
"cuisine" : "Traditional Irish", "address" : { "building" : "202-24", "coord" : [-73.925044200000002, 40.5595462],
"street" : "Rockaway Point Boulevard", "zipcode" : "11697" }, "borough" : "Queens", "grades" : [...] }

Para obtener más información sobre pre-imágenes y post-imágenes, consulta Change Streams con preimágenes y postimágenes de documentos en el manual de MongoDB Server.

Para saber más sobre las change streams, consulta Change Streams en el manual de MongoDB Server.

Para aprender más sobre cualquiera de los métodos o tipos analizados en esta guía, consulta la siguiente documentación de API: