El patrón de bucket separa largas series de datos en objetos distintos. Separar grandes series de datos en grupos más pequeños puede mejorar los patrones de acceso a las consultas y simplificar la lógica de la aplicación. La segmentación es útil cuando se tienen objetos similares relacionados con una entidad central, como las operaciones bursátiles realizadas por un solo usuario.
Puede usar el patrón de cubo para la paginación, agrupando sus datos según los elementos que su aplicación muestra por página. Este enfoque utiliza el modelo de datos flexible de MongoDB para almacenar datos según las necesidades de sus aplicaciones.
Tip
Las colecciones de series de tiempo aplican automáticamente el patrón de agrupación y son adecuadas para la mayoría de las aplicaciones que implican la agrupación de datos de series de tiempo.
Acerca de esta tarea
Considere el siguiente esquema que rastrea las operaciones bursátiles. El esquema inicial no utiliza el patrón de cubo y almacena cada operación en un documento individual.
db.trades.insertMany( [ { "ticker" : "MDB", "customerId": 123, "type" : "buy", "quantity" : 419, "date" : ISODate("2023-10-26T15:47:03.434Z") }, { "ticker" : "MDB", "customerId": 123, "type" : "sell", "quantity" : 29, "date" : ISODate("2023-10-30T09:32:57.765Z") }, { "ticker" : "GOOG", "customerId": 456, "type" : "buy", "quantity" : 50, "date" : ISODate("2023-10-31T11:16:02.120Z") } ] )
La aplicación muestra las operaciones de acciones realizadas por un solo cliente a la vez y muestra 10 operaciones por página. Para simplificar la lógica de la aplicación, utilice el patrón de cubeta para agrupar las operaciones por customerId en grupos de 10.
Pasos
Agrupa los datos por customerId.
Reorganiza el esquema para que haya un solo documento para cada customerId:
{ "customerId": 123, "history": [ { "type": "buy", "ticker": "MDB", "qty": 419, "date": ISODate("2023-10-26T15:47:03.434Z") }, { "type": "sell", "ticker": "MDB", "qty": 29, "date": ISODate("2023-10-30T09:32:57.765Z") } ] }, { "customerId": 456, "history": [ { "type" : "buy", "ticker" : "GOOG", "quantity" : 50, "date" : ISODate("2023-10-31T11:16:02.120Z") } ] }
Con el patrón del cubo:
Los documentos con valores comunes de
customerIdse condensan en un único documento, con elcustomerIdcomo un campo de nivel superior.Las transacciones de ese cliente se agrupan en un campo de matriz incrustado, llamado
history.
Agregue un identificador y una cuenta para cada cubeta.
1 db.trades.drop() 2 3 db.trades.insertMany( 4 [ 5 { 6 "_id": "123_1698349623", 7 "customerId": 123, 8 "count": 2, 9 "history": [ 10 { 11 "type": "buy", 12 "ticker": "MDB", 13 "qty": 419, 14 "date": ISODate("2023-10-26T15:47:03.434Z") 15 }, 16 { 17 "type": "sell", 18 "ticker": "MDB", 19 "qty": 29, 20 "date": ISODate("2023-10-30T09:32:57.765Z") 21 } 22 ] 23 }, 24 { 25 "_id": "456_1698765362", 26 "customerId": 456, 27 "count": 1, 28 "history": [ 29 { 30 "type" : "buy", 31 "ticker" : "GOOG", 32 "quantity" : 50, 33 "date" : ISODate("2023-10-31T11:16:02.120Z") 34 } 35 ] 36 }, 37 ] 38 )
El valor del campo _id es una concatenación del customerId y la primera hora de negociación en segundos (desde la época unix) en el campo history.
El campo count indica cuántos elementos hay en la matriz history de ese documento. El campo count se utiliza para implementar la lógica de paginación.
Próximos pasos
Después de actualizar tu esquema para utilizar el patrón de bucket, actualiza la lógica de tu aplicación para la lectura y escritura de datos. Consulta las siguientes secciones:
Query para datos con el patrón Bucket
En el esquema actualizado, cada documento contiene los datos de una sola página de la aplicación. Puede usar el campo _id y count para determinar cómo devolver y actualizar datos.
Para query datos en la página adecuada, usa una consulta regex para devolver datos de un(a) customerId especificado(a), y usa skip para regresar a los datos de la página correcta. La consulta regex en _id utiliza el índice _id por defecto, lo que da como resultado consultas eficientes sin la necesidad de un índice adicional.
La siguiente query devuelve datos para la primera página de transacciones del cliente 123:
db.trades.find( { "_id": /^123_/ } ).sort( { _id: 1 } ).limit(1)
Para devolver datos de páginas posteriores, especifique un valor de skip una unidad menor a la página para la que desea mostrar los datos. Por ejemplo, para mostrar datos de la página 10, ejecute la siguiente query:
db.trades.find( { "_id": /^123_/ } ).sort( { _id: 1 } ).skip(9).limit(1)
Nota
La query anterior no devuelve resultados porque los datos de muestra sólo contienen documentos de la primera página.
Insertar datos con el patrón Bucket
Ahora que el esquema utiliza el bucket pattern (patrón de cubo), actualiza la lógica de tu aplicación para insertar nuevas transacciones en el bucket correcto. Utiliza un comando de actualización para insertar la operación en el segmento correspondiente con el customerId y segmento adecuados.
El siguiente comando inserta una nueva operación para customerId: 123:
db.trades.updateOne( { "_id": /^123_/, "count": { $lt: 10 } }, { "$push": { "history": { "type": "buy", "ticker": "MSFT", "qty": 42, "date": ISODate("2023-11-02T11:43:10") } }, "$inc": { "count": 1 }, "$setOnInsert": { "_id": "123_1698939791", "customerId": 123 } }, { upsert: true } )
La aplicación muestra 10 operaciones por página. El filtro de actualización busca un documento para customerId: 123 donde el count sea menor que 10, lo que significa que ese bucket no contiene una página completa de datos.
Si hay un documento que coincide con
"_id": /^123_/y sucountes menor que 10, el comando de actualización inserta la nueva transacción en la matrizhistorydel documento coincidente.Si no hay un documento que coincida, el comando de actualización inserta un nuevo documento con la nueva operación (porque
upsertestrue). El campo_iddel nuevo documento es una concatenación decustomerIdy el tiempo en segundos desde la Unix epoch de la operación.
La lógica para los comandos de actualización evita arreglos sin límites asegurando que ningún arreglo history contenga más de 10 documentos.
Después de ejecutar la operación de actualización, la colección trades contiene los siguientes documentos:
[ { _id: '123_1698349623', customerId: 123, count: 3, history: [ { type: 'buy', ticker: 'MDB', qty: 419, date: ISODate("2023-10-26T15:47:03.434Z") }, { type: 'sell', ticker: 'MDB', qty: 29, date: ISODate("2023-10-30T09:32:57.765Z") }, { type: 'buy', ticker: 'MSFT', qty: 42, date: ISODate("2023-11-02T11:43:10.000Z") } ] }, { _id: '456_1698765362', customerId: 456, count: 1, history: [ { type: 'buy', ticker: 'GOOG', quantity: 50, date: ISODate("2023-10-31T11:16:02.120Z") } ] } ]
Resultados
Después de implementar el patrón bucket, no necesitas incorporar lógica de paginación para devolver resultados en tu aplicación. La forma en que se almacenan los datos coincide con la forma en que se utilizan en la aplicación.