Definición
Novedades en MongoDB 7.0 (y 6.0.9).
Si un Si el flujo de cambios contiene eventos grandes que superan los 16 MB,BSONObjectTooLarge se devuelve una excepción. A partir de MongoDB 7.0 6.0.9(y), se puede usar una $changeStreamSplitLargeEvent etapa 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 solicite imágenes previas ni posteriores del documento a menos que su aplicación las requiera. Esto genera campos
fullDocumentyfullDocumentBeforeChangeen la mayoría de los casos, que suelen ser los objetos más grandes en un evento de cambio.Utilice una etapa para incluir solo los campos necesarios para su aplicación. Esto reduce el tamaño del evento de cambio y evita el tiempo adicional que supone dividir eventos grandes en fragmentos. Esto permite devolver más eventos de cambio en cada
$projectlote.
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 se devuelva el máximo número de campos en el primero. 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.
Comience en el próximo evento si se reanuda desde el fragmento final de 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 del fragmento, 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 } } )
Cree un cursor de flujo de cambios para monitorear los cambios en myCollection db.collection.watch()usando:
myChangeStreamCursor = db.myCollection.watch( [ { $changeStreamSplitLargeEvent: {} } ], { fullDocument: "required", fullDocumentBeforeChange: "required" } )
Para el evento de flujo de cambio:
fullDocument: "required"Incluye la imagen posterior del documento.fullDocumentBeforeChange: "required"Incluye la preimagen del documento.
Para obtener más detalles, consulte $changeStream.
Actualice el documento en myCollection, lo que también produce un evento de flujo de cambios con las imágenes anteriores y posteriores del documento:
db.myCollection.updateOne( { _id: 0 }, { $set: { largeField: "b".repeat( 16 * 1024 * 1024 - 1024 ) } } )
largeField ahora contiene la letra repetida b.
Recupere los fragmentos de myChangeStreamCursor utilizando el método y almacene los fragmentos en next() objetos firstFragment llamados, secondFragment thirdFragmenty:
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 tiene un tamaño aproximado de 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 Conjuntos de datos de ejemplo de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de ejemplo,consulte "Comenzar" en la documentación del controlador MongoDB.NET/C#.
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 MongoDB.NET/C# para agregar una $changeStreamSplitLargeEvent etapa a una canalización de agregación, llame 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();
Puede utilizar tanto el watch() método como el aggregate() método para ejecutar una $changeStreamSplitLargeEvent operación. $changeStreamSplitLargeEvent devuelve un ChangeStreamCursor cuando pasa la canalización de agregación al método watch() en un Collection objeto MongoDB. $changeStreamSplitLargeEvent devuelve un AggregationCursor cuando pasa la canalización de agregación al método added().
Importante
Reanudabilidad de $changeStreamSplitLargeEvent
Si se pasa un flujo de cambios al método added(), este no se puede reanudar. Un flujo de cambios solo se reanuda si se pasa al método watch(). Para obtener más información sobre la reanudabilidad, consulte Reanudar un flujo de cambios.
El siguiente ejemplo divide los eventos que superan 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 flujo de cambios, consulte Eventos de cambio.
Para aprender más sobre las etapas relacionadas del pipeline, consulta la guía $changeStream.