Definición
Novedades en MongoDB 7.0 (y 6.0.9).
Si un flujo de cambios tiene eventos grandes que superan los 16 MB, se devuelve una excepción BSONObjectTooLarge. A partir de MongoDB 7.0 (y 6.0.9), puede usar una etapa $changeStreamSplitLargeEvent para dividir los eventos en fragmentos más pequeños.
Solo debe usar $changeStreamSplitLargeEvent cuando sea estrictamente necesario. Por ejemplo, si su aplicación requiere imágenes completas previas o posteriores al documento y genera eventos grandes que superan los 16 MB, use $changeStreamSplitLargeEvent.
Antes de decidir usar $changeStreamSplitLargeEvent, debería intentar reducir el tamaño del evento de cambio. Por ejemplo:
No solicites imágenes previas o posteriores de documentos a menos que tu aplicación las requiera. Esto genera los campos
fullDocumentyfullDocumentBeforeChangeen más casos, que suelen ser los objetos más grandes en un evento de cambio.Usa una etapa
$projectpara incluir solo los campos necesarios para tu aplicación. Esto reduce el tamaño del evento de cambio y evita el tiempo adicional de dividir grandes eventos en fragmentos. Esto permite que se devuelvan más eventos de cambio en cada lote.
Solo puede tener una etapa $changeStreamSplitLargeEvent en su pipeline, y debe ser la última. Solo puede usar $changeStreamSplitLargeEvent en un pipeline $changeStream.
$changeStreamSplitLargeEvent sintaxis:
{ $changeStreamSplitLargeEvent: {} }
Comportamiento
$changeStreamSplitLargeEvent divide los eventos que superan 16 MB en fragmentos y devuelve los fragmentos secuencialmente utilizando el cursor de flujo de cambio.
Los fragmentos se dividen para que la mayor cantidad de campos se devuelvan en el primer fragmento. Esto garantiza que el contexto del evento se devuelva lo más rápido posible.
Cuando el evento de cambio se divide, solo se utiliza el tamaño de los campos de nivel superior. $changeStreamSplitLargeEvent no procesa ni divide recursivamente los subdocumentos. Por ejemplo, si usas una etapa $project para crear un evento de cambio con un solo campo de 20 MB de tamaño, el evento no se divide y la etapa retornará un error.
Cada fragmento tiene un token de reanudación. Una secuencia que se reanuda usando el token de un fragmento:
Iniciar una nueva secuencia a partir del siguiente fragmento.
Comienza en el siguiente evento si estás reanudando a partir del fragmento final en la secuencia.
Cada fragmento de un evento incluye un documento splitEvent:
splitEvent: { fragment: <int>, of: <int> }
La siguiente tabla describe los campos.
Campo | Descripción |
|---|---|
| Índice de fragmentos, comenzando en 1. |
| Número total de fragmentos para el evento. |
Ejemplos
El escenario de ejemplo en esta sección muestra el uso de $changeStreamSplitLargeEvent con una nueva colección llamada myCollection.
Cree myCollection e inserte un documento con poco menos de 16 MB de datos:
db.myCollection.insertOne( { _id: 0, largeField: "a".repeat( 16 * 1024 * 1024 - 1024 ) } )
largeField contiene la letra repetida a.
Habilite changeStreamPreAndPostImages myCollectionpara, lo que permite que un flujo de cambios recupere un documento como estaba antes de una actualización (pre-imagen) y después de una actualización (post-imagen):
db.runCommand( { collMod: "myCollection", changeStreamPreAndPostImages: { enabled: true } } )
Crea un cursor de flujo de cambios para supervisar los cambios en myCollection utilizando db.collection.watch():
myChangeStreamCursor = db.myCollection.watch( [ { $changeStreamSplitLargeEvent: {} } ], { fullDocument: "required", fullDocumentBeforeChange: "required" } )
Para el evento de flujo de cambio:
fullDocument: "required"incluye la imagen posterior al documento.fullDocumentBeforeChange: "required"incluye la preimagen del documento.
Para obtener más detalles, consulte $changeStream.
Actualiza el documento en myCollection, lo que también produce un evento de flujo de cambios con las imágenes previas y posteriores del documento:
db.myCollection.updateOne( { _id: 0 }, { $set: { largeField: "b".repeat( 16 * 1024 * 1024 - 1024 ) } } )
largeField ahora contiene la letra repetida b.
Recupera los fragmentos de myChangeStreamCursor utilizando el método next() y almacena los fragmentos en objetos llamados firstFragment, secondFragment y thirdFragment:
const firstFragment = myChangeStreamCursor.next() const secondFragment = myChangeStreamCursor.next() const thirdFragment = myChangeStreamCursor.next()
Mostrar firstFragment.splitEvent:
firstFragment.splitEvent
Salida con los detalles del fragmento:
splitEvent: { fragment: 1, of: 3 }
De manera similar, secondFragment.splitEvent y thirdFragment.splitEvent devuelven:
splitEvent: { fragment: 2, of: 3 } splitEvent: { fragment: 3, of: 3 }
Para examinar las claves de objeto para firstFragment:
Object.keys( firstFragment )
Salida:
[ '_id', 'splitEvent', 'wallTime', 'clusterTime', 'operationType', 'documentKey', 'ns', 'fullDocument' ]
Para examinar el tamaño en bytes de firstFragment.fullDocument:
bsonsize( firstFragment.fullDocument )
Salida:
16776223
secondFragment contiene la preimagen fullDocumentBeforeChange, que tiene un tamaño aproximado de 16 MB. El siguiente ejemplo muestra las claves de objeto para secondFragment:
Object.keys( secondFragment )
Salida:
[ '_id', 'splitEvent', 'fullDocumentBeforeChange' ]
thirdFragment Contiene el campo updateDescription, que ocupa aproximadamente 16 MB. El siguiente ejemplo muestra las claves de objeto para thirdFragment:
Object.keys( thirdFragment )
Salida:
[ '_id', 'splitEvent', 'updateDescription' ]
Los ejemplos de C# en esta página utilizan la base de datos sample_mflix de la conjuntos de datos de muestra de Atlas. Para aprender cómo crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de muestra, consulta Primeros pasos en la documentación del controlador .NET/C# de MongoDB.
La siguiente clase Movie modela los documentos en la colección sample_mflix.movies:
public class Movie { public ObjectId Id { get; set; } public int Runtime { get; set; } public string Title { get; set; } public string Rated { get; set; } public List<string> Genres { get; set; } public string Plot { get; set; } public ImdbData Imdb { get; set; } public int Year { get; set; } public int Index { get; set; } public string[] Comments { get; set; } [] public DateTime LastUpdated { get; set; } }
Nota
ConventionPack para Pascal Case
Las clases de C# en esta página utilizan Pascal case para los nombres de sus propiedades, pero los nombres de los campos en la colección de MongoDB utilizan camel case. Para tener en cuenta esta diferencia, se puede usar el siguiente código para registrar un ConventionPack cuando la aplicación se inicie:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
Para usar el controlador .NET/C# de MongoDB para añadir una etapa $changeStreamSplitLargeEvent a una pipeline de agregación, llama a ChangeStreamSplitLargeEvent()método en un PipelineDefinition objeto.
El siguiente ejemplo crea una etapa de pipeline que divide eventos que superan 16 MB en fragmentos y los devuelve secuencialmente en un cursor de flujo de cambios:
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<Movie>>() .ChangeStreamSplitLargeEvent();
Puedes utilizar tanto el método watch() como el método aggregate() para ejecutar una operación $changeStreamSplitLargeEvent. $changeStreamSplitLargeEvent devuelve un ChangeStreamCursor cuando se pasa el pipeline de agregación al método watch() en un objeto de MongoDB Collection. $changeStreamSplitLargeEvent devuelve un AggregationCursor cuando pasas el pipeline de agregación al método aggregate().
Importante
$changeStreamSplitLargeEvent Resumibility
Si pasas un flujo de cambios al método aggregate(), el flujo de cambios no puede reanudarse. Un flujo de cambios solo se reanuda si lo pasas al método watch(). Para obtener más información sobre la reanudabilidad, consulta Reanudar una Change Stream (flujo de cambios).
El siguiente ejemplo divide los eventos que superan los 16 MB en fragmentos y los devuelve secuencialmente en un ChangeStreamCursor:
const pipeline = [{ changeStreamSplitLargeEvent: {} }]; const changeStream = collection.watch(pipeline); return changeStream;
Obtén más información
Para obtener más información sobre las notificaciones de flujos de cambios, consulta Eventos de cambio.
Para aprender más sobre las etapas relacionadas del pipeline, consulta la guía $changeStream.