EventoObtenha 50% de desconto no seu ingresso para MongoDB.local Londres em outubro 2. Use o código WEB50Saiba mais >>
Desenvolvedor MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
MongoDBchevron-right

Como manter várias versões de um registro no MongoDB (atualizações 2024)

John Page6 min read • Published Aug 12, 2024 • Updated Aug 12, 2024
Framework de agregaçãoMongoDB
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Ao longo dos anos, houve vários métodos propostos para o controle de versão de dados no MongoDB. O controle de versão de dados significa ser capaz de obter facilmente não apenas a versão mais recente de um documento ou documentos, mas também visualizar e consultar a forma como os documentos eram em um determinado ponto no tempo.
Houve a publicação do blog de Asya kamski escrita aproximadamente 10 anos atrás, uma atualização de Paulo feito (autor de Practical MongoDB Aggregations) e também informações no site da MongoDB sobre o padrão de versão de 2019.
Eles mantêm duas coleções distintas de dados – uma com a versão mais recente e outra com versões ou atualizações anteriores, permitindo reconstruí-las.
No entanto, desde então, houve mudanças sísmicas de baixo nível nos recursos de atualização e agregação do MongoDB. Aqui, mostrarei uma maneira relativamente simples de manter um histórico de documentos ao atualizar sem manter coleções adicionais.
Para fazer isso, usamos atualizações expressivas, também chamadas de atualizações do pipeline de agregação. Em vez de passar um objeto com operadores de atualização como segundo argumento para atualizar, coisas como $push e $set, expressamos nossa atualização como um pipeline de agregação, com um conjunto ordenado de alterações. Ao fazer isso, podemos não apenas fazer alterações, mas também pegar os valores anteriores de todos os campos que alteramos e registrá-los em um campo diferente como histórico.
O exemplo mais simples disso seria usar o seguinte como o parâmetro de atualização para uma operação updateOne.
Isso definiria explicitamente a como 5 , mas também definiria previous_a como qualquer que fosse o a antes da atualização. No entanto, isso só nos daria uma retrospectiva do histórico de uma única mudança.
Antes de:
Depois:
O que queremos fazer é pegar todos os campos que mudamos e construir um objeto com esses valores anteriores e, em seguida, empurrá-lo para uma array — teoricamente, assim:
O acima não funciona porque a parte $push em negrito é um operador de atualização, não uma sintaxe de agregação, portanto, dá um erro de sintaxe. Em vez disso, o que precisamos fazer é reescrever o push como uma operação de array, da seguinte forma:
Para explicar o que está acontecendo aqui, quero adicionar um objeto, { _updateTime: "$$NOW", a:"$a",b:"$b"}, à matriz no início. Não posso usar $push, pois essa é uma sintaxe de atualização, e a sintaxe expressiva trata da geração de um documento com novas versões para os campos, ou seja, apenas $set. Portanto, preciso definir a matriz como a matriz anterior com um novo valor anexado.
Usamos $concatArrays para unir duas arrays, então preparo meu único documento contendo os valores antigos para campos em uma array. Em seguida, a nova array é a minha array concatenada com a array antiga.
Eu uso $ifNUll para dizer se o valor anteriormente era nulo ou ausente, trate-o como uma array vazia, então da primeira vez, ele realmente faz history = [{ _updateTime: "$$NOW", a:"$a",b:"$b"}] + [].
Antes de:
Depois:
É um pouco difícil de escrever, mas se escrevermos o código para demonstrar isso e declará-lo como objetos separados, ele ficará muito mais claro. Veja a seguir um script que você pode executar no shell do MongoDB colando-o ou carregando -o com load("versioning.js").
Este código primeiro gera alguns registros simples:
(index)_idcampo_1campo_2campo_3campo_4dateUpdated
00344919742024-04-15T13:30:12.788Z
111394342024-04-15T13:30:12.836Z
22513096932024-04-15T13:30:12.849Z
33294421852024-04-15T13:30:12.860Z
4441351572024-04-15T13:30:12.866Z
5508556282024-04-15T13:30:12.874Z
66855624782024-04-15T13:30:12.883Z
77272396252024-04-15T13:30:12.895Z
88704040302024-04-15T13:30:12.905Z
9969131392024-04-15T13:30:12.914Z
Em seguida, modificamos os dados que registram o histórico como parte da operação de atualização.
Agora temos registros que se parecem com isso — com os valores atuais, mas também uma matriz refletindo quaisquer alterações.
Agora podemos usar um pipeline de agregação para recuperar qualquer versão anterior de cada documento. Para fazer isso, primeiro filtramos o histórico para incluir apenas as alterações até o ponto no tempo que queremos. Em seguida, os mesclamos em ordem:
Essa técnica surgiu através da discussão das necessidades de um cliente MongoDB. Eles tinham exatamente esse caso de uso para manter o histórico e o atual e para poder consultar e recuperar qualquer um deles sem precisar manter uma cópia completa do documento. É uma escolha ideal se as mudanças forem relativamente pequenas. Ele também pode ser adaptado para registrar apenas uma entrada de histórico se o valor do campo for diferente, o que permite computar deltas mesmo ao substituir todo o registro.
Como nota de advertência, o controle de versão dentro de um documento como este tornará os documentos maiores. Isso também significa uma variedade cada vez maior de edições. Se você acredita que pode haver centenas ou milhares de alterações, essa técnica não é adequada e o histórico deve ser gravado em um segundo documento usando uma transação. Para fazer isso, execute a atualização com findOneAndUpdate e retorne os campos que você está alterando dessa chamada para inserir em uma coleção de histórico.
Este não pretende ser um tutorial passo a passo, embora você possa tentar os exemplos acima e ver como funciona. É uma das muitas modelagem de dados sofisticada
técnicas que você pode usar para construir serviços de alto desempenho no MongoDB e MongoDB Atlas. Se você precisar de controle de versão de registro, poderá usar isso. Se não, então talvez passe um pouco mais de tempo vendo o que você pode criar com o aggregation pipeline, um mecanismo de processamento de dados completo para Turing que é executado junto com seus dados, economizando tempo e custo de fechá-los para o cliente processar. Saiba mais sobre aggregation.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.
Iniciar a conversa

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Artigo

Uma atualização sobre o compromisso contínuo do MongoDB com Swift


Jul 12, 2024 | 4 min read
Artigo

ORMs, ODMs e bibliotecas do MongoDB


Aug 28, 2024 | 3 min read
Início rápido

Pipeline de agregação Java


Mar 01, 2024 | 8 min read
Tutorial

Construindo com padrões: o Padrão Outlier


May 16, 2022 | 3 min read