MongoDB: Como posso carregar dados recentes na memória usando o campo / índice ObjectID padrão?

A premissa aqui é como carregar um subconjunto de dados (neste caso, dados recentes) usando o índice padrão no _idcampo e o conteúdo padrão desse campo ( ObjectID).

De acordo com as ObjectIDespecificações, cada um ObjectIDcomeça com um valor de 4 bytes que representa os segundos desde a época do Unix. Portanto, devemos ser capazes de aproveitar esse valor de tempo para selecionar um intervalo apropriado de valores.

Assim que tivermos nossos critérios, é simplesmente uma questão de garantir que todos os dados sejam carregados na memória. Se você deseja carregar todos os dados em um índice, ou em uma coleção, na memória, você pode usar o comando touch, mas para um subconjunto desses dados, uma abordagem diferente é necessária.

Para garantir que todos os dados sejam carregados, usaremos o hint()método para especificar o índice usado (remove qualquer ambigüidade) e o explain()método (para garantir que a consulta seja executada até o fim).

O uso do método hint é direto, mas o uso de explain é menos óbvio. O motivo para isso é garantir que a consulta seja executada em sua totalidade. Se você o deixou de fora, você obteria o primeiro lote de resultados de volta (e um cursor) e, em seguida, teria que iterar naquele cursor até que os resultados se esgotassem.

Como o explain precisa ver toda a operação para fornecer informações de tempo, toda a consulta é executada e, portanto, todos os dados são carregados na memória.

Finalmente, podemos manipular a própria consulta para carregar apenas o índice ou o índice e os dados (semelhante ao comando de toque), se desejarmos ser seletivos. Agora só precisamos de nossos critérios, e isso é relativamente fácil de construir:

Primeiro, este pequeno snippet getTimefornece um tempo de época em segundos ( retorna em milis) e o armazena na variável decTime:

decTime = Math.round(((new Date().getTime())/1000));

É muito fácil transformar isso em um tempo há 3 dias, por exemplo:

last3Days = Math.round(((new Date().getTime() - (3 * 24 * 60 * 60))/1000));

No entanto, o ObjectIDé armazenado em hexadecimal (execute new ObjectId()no shell para ver um exemplo), portanto, precisamos converter. Novamente, isso é relativamente fácil:

hexTime = decTime.toString(16);

Agora, tudo o que precisamos fazer é adicionar preenchimento e passar nossa string construída para criar nosso ObjectID:

testId = ObjectId(hexTime+"0000000000000000");

Aqui está um exemplo de execução no shell:

> decTime = Math.round(((new Date().getTime())/1000));
1398422583
> last3Days = Math.round(((new Date().getTime() - (3 * 24 * 60 * 60))/1000));
1398422690
> hexTime = decTime.toString(16);
535a3c37
> hex3Days = last3Days.toString(16);
535a3ca2
> testId = ObjectId(hexTime+"0000000000000000");
ObjectId("535a3c370000000000000000")
> historicId = ObjectId(hex3Days+"0000000000000000");
ObjectId("535a3ca20000000000000000")

Finalmente, precisamos colocar tudo isso junto e usar o ObjectIdque construímos como nosso critério de consulta. Novamente, de uma forma geral, e assumindo _idcomo o campo indexado que se pareceria com isto:

db.collName.find({"_id" : {"$gt" : historicId}}).hint({"_id" : 1}).explain();

Colocar tudo isso em uma função com alguns parâmetros permite que seja facilmente reutilizado e você pode encontrar um exemplo muito básico nesta essência: prejheat.js .

Observação: originalmente escrevi isso como uma pergunta e resposta no SO , então se você achar útil, sinta-se à vontade para enviar um representante para mim também.