El patrón de cubos separa las series de datos largas en objetos distintos. Separar grandes conjuntos de datos en grupos más pequeños puede mejorar los patrones de acceso a query y simplificar la lógica de la aplicación. El bucketing es útil cuando tienes objetos similares que se relacionan con una entidad central, como las operaciones con acciones realizadas por un único usuario.
Puedes utilizar el patrón de bucket para la paginación agrupando tus datos según los elementos que tu aplicación muestra por página. Este enfoque utiliza el modelo de datos flexible de MongoDB para almacenar datos según las necesidades de datos de tus 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 de acciones. El esquema inicial no utiliza el patrón bucket 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 de cubo:
Los documentos con valores comunes de
customerIdse condensan en un único documento, con elcustomerIdcomo un campo de nivel superior.Las transacciones para ese cliente se agrupan en un campo de arreglo 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 el arreglo 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.
Inserte 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 update inserta la nueva operación en el arreglohistorydel 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.