O padrão de bucket separa longas séries de dados em objetos distintos. Separar grandes séries de dados em grupos menores pode melhorar os padrões de acesso à consulta e simplificar a lógica do aplicativo. O bucketing é útil quando você tem objetos semelhantes relacionados a uma entidade central, como negociações de ações feitas por um único usuário.
Você pode utilizar o padrão bucket para paginação, agrupando seus dados com base nos elementos que seu aplicativo mostra por página. Essa abordagem utiliza o modelo de dados flexível do MongoDB para armazenar dados de acordo com os dados que seus aplicativos precisam.
Dica
As coleções de séries temporais aplicam o padrão de bucket automaticamente e são adequadas para a maioria das aplicações que envolvem o agrupamento de dados de séries temporais.
Sobre esta tarefa
Considere o esquema a seguir que acompanha as negociações de ações. O esquema inicial não utiliza o padrão de bucket e armazena cada negociação em um 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") } ] )
O aplicativo mostra transações de ações feitas por um único cliente de cada vez e mostra 10 transações por página. Para simplificar a lógica do aplicativo, use o padrão bucket para agrupar as transações por customerId em grupos de 10.
Passos
Agrupe os dados por customerId.
Reorganizar o esquema para ter um único 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") } ] }
Com o padrão de bucket:
Os documentos com valores
customerIdcomuns são condensados em um único documento, no qualcustomerIdé um campo de nível superior.As negociações desse cliente são agrupadas em um campo de array incorporado, chamado
history.
Adicione um identificador e conte para cada bucket.
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 )
O valor do campo _id é uma concatenação de customerId mais o tempo da primeira negociação em segundos (a partir da era UNIX) no campo history .
O campo count indica quantos elementos estão na array history desse documento. O campo count é usado para implementar a lógica de paginação.
Próximos passos
Depois de atualizar o esquema para usar o padrão de bucket, atualize a lógica do aplicativo para ler e gravar dados. Consulte as seções a seguir:
Consultar dados com o padrão de bucket
No esquema atualizado, cada documento contém dados para uma única página no aplicativo. Você pode usar os campos _id e count para determinar como retornar e atualizar dados.
Para consultar dados na página apropriada, use uma query regex para obter dados de um customerId especificado e use skip para retornar aos dados da página correta. A query regex em _id usa índice _id padrão, o que resulta em consultas de alto desempenho sem a necessidade de um índice adicional.
A consulta a seguir retorna dados da primeira página de negociações para o cliente 123:
db.trades.find( { "_id": /^123_/ } ).sort( { _id: 1 } ).limit(1)
Para retornar dados para páginas posteriores, especifique um valor de skip menor do que a página para a qual você deseja mostrar dados. Por exemplo, para mostrar dados para a página 10, execute a seguinte query:
db.trades.find( { "_id": /^123_/ } ).sort( { _id: 1 } ).skip(9).limit(1)
Observação
A query anterior não retorna resultados porque os dados de amostra contêm apenas documentos da primeira página.
Inserir dados com o padrão Bucket
Agora que o esquema usa o padrão de bucket, atualize a lógica do aplicativo para inserir novas negociações no bucket correto. Use o comando update para inserir a negociação no bucket com o customerId e o bucket apropriados.
O comando a seguir insere uma nova negociação 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 } )
O aplicação exibe 10 transações por página. O filtro de atualização procura um documento para customerId: 123 onde o count é menor que 10, o que significa que o bucket não contém uma página inteira de dados.
Se houver um documento que corresponda a
"_id": /^123_/e seucountfor menor que 10, o comando de atualização empurrará a nova transação para a arrayhistorydo documento correspondente.Se não houver um documento correspondente, o comando de atualização inserirá um novo documento com a nova transação (porque
upsertétrue). O campo_iddo novo documento é uma concatenação docustomerIde o tempo em segundos desde a Era UNIX da transação.
A lógica para comandos de atualização evita arrays ilimitadas, garantindo que nenhuma array history contenha mais de 10 documentos.
Depois de executar a operação de atualização, a coleção trades tem os seguintes 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
Depois de implementar o padrão de bucket, você não precisa incorporar a lógica de paginação para retornar resultados em seu aplicação. A forma como os dados são armazenados corresponde à forma como são utilizados no aplicação.