Todos os dias, recebo um estoque de documentos (uma atualização). O que eu quero fazer é inserir cada item que ainda não existe.
- Também quero acompanhar a primeira vez que os inseri e a última vez que os vi em uma atualização.
- Não quero documentos duplicados.
- Não quero remover um documento que foi salvo anteriormente, mas não está na minha atualização.
- 95% (estimado) dos registros não são modificados diariamente.
Estou usando o driver Python (pymongo).
O que atualmente faço é (pseudo-código):
for each document in update:
existing_document = collection.find_one(document)
if not existing_document:
document['insertion_date'] = now
else:
document = existing_document
document['last_update_date'] = now
my_collection.save(document)
Meu problema é que é muito lento (40 minutos para menos de 100.000 registros e tenho milhões deles na atualização). Tenho certeza de que há algo embutido para fazer isso, mas o documento para update () é mmmhhh .... um pouco mais conciso ... ( http://www.mongodb.org/display/DOCS/Updating )
Alguém pode aconselhar como fazê-lo mais rápido?
No MongoDB 2.4, você pode usar $ setOnInsert ( http://docs.mongodb.org/manual/reference/operator/setOnInsert/ )
Defina 'inserttion_date' usando $ setOnInsert e 'last_update_date' usando $ set no seu comando upsert.
Para transformar seu pseudocódigo em um exemplo de trabalho:
fonte
Você sempre pode criar um índice exclusivo, o que faz com que o MongoDB rejeite um salvamento conflitante. Considere o seguinte feito usando o shell mongodb:
fonte
Você pode usar Upsert com o operador $ setOnInsert.
fonte
1. Use Atualização.
Com base na resposta de Van Nguyen acima, use update em vez de save. Isso lhe dá acesso à opção de upsert.
NOTA : Este método substitui o documento inteiro quando encontrado ( Dos documentos )
1.a. Use $ set
Se você deseja atualizar uma seleção do documento, mas não a coisa toda, pode usar o método $ set com a atualização. (novamente, nos documentos ) ... Então, se você deseja definir ...
Enviar como ...
Isso ajuda a evitar a substituição acidental de todos os seus documentos
{ name: 'jason borne' }
.fonte
Resumo
Note, presumo que o PyMongo mude para se adequar ao seu idioma de escolha.
Instruções:
Crie a coleção com um índice com unique = true para não obter registros duplicados.
Faça uma iteração sobre seus registros de entrada, criando lotes deles com cerca de 15.000 registros. Para cada registro no lote, crie um ditado que consiste nos dados que você deseja inserir, presumindo que cada um será um novo registro. Adicione os carimbos de data / hora 'criados' e 'atualizados' a estes. Emita isso como um comando de inserção em lote com o sinalizador 'ContinueOnError' = true, para que a inserção de todo o resto aconteça mesmo se houver uma chave duplicada (o que parece haver). Isso vai acontecer muito rápido. Inserções em massa de rochas, obtive níveis de desempenho de 15k / segundo. Para obter mais notas sobre o ContinueOnError, consulte http://docs.mongodb.org/manual/core/write-operations/
As inserções de registro acontecem MUITO rápido, então você será feito com essas inserções em pouco tempo. Agora, é hora de atualizar os registros relevantes. Faça isso com uma recuperação em lote, muito mais rápido que um de cada vez.
Itere novamente todos os seus registros de entrada, criando lotes de 15 mil ou mais. Extraia as chaves (melhor se houver uma chave, mas não puderem ser ajudadas se não houver). Recupere esse monte de registros do Mongo com uma consulta db.collectionNameBlah.find ({field: {$ in: [1, 2,3 ...}). Para cada um desses registros, determine se há uma atualização e, se houver, emita a atualização, incluindo a atualização do carimbo de data / hora 'atualizado'.
Infelizmente, devemos observar que o MongoDB 2.4 e abaixo NÃO incluem uma operação de atualização em massa. Eles estão trabalhando nisso.
Principais pontos de otimização:
fonte
Eu não acho que o mongodb suporta esse tipo de upserting seletivo. Eu tenho o mesmo problema que o LeMiz, e o uso da atualização (critérios, newObj, upsert, multi) não funciona direito ao lidar com um carimbo de data / hora 'criado' e 'atualizado'. Dada a seguinte declaração upsert:
Cenário # 1 - o documento com 'nome' de 'abc' não existe: o novo documento é criado com 'name' = 'abc', 'created' = 14-07-2010 11:11:11 e 'updated' = 2010-07-14 11:11:11.
Cenário # 2 - o documento com 'nome' de 'abc' já existe com o seguinte: 'name' = 'abc', 'created' = 2010-07-12 09:09:09 e 'updated' = 2010-07 -13 10:10:10. Após a upsert, o documento agora seria o mesmo que o resultado no cenário 1. Não há como especificar em um upsert quais campos serão definidos ao inserir e quais serão deixados em paz se forem atualizados.
Minha solução foi criar um índice exclusivo nos campos de critério , executar uma inserção e imediatamente depois executar uma atualização apenas no campo 'atualizado'.
fonte
Em geral, o uso da atualização é melhor no MongoDB, pois ele apenas criará o documento, se ainda não existir, embora não tenha certeza de como trabalhar isso com o seu adaptador python.
Segundo, se você precisar apenas saber se esse documento existe ou não, count () que retorna apenas um número será uma opção melhor do que o find_one, que supostamente transfere todo o documento do MongoDB, causando tráfego desnecessário.
fonte