Posso consultar o MongoDB ObjectId por data?

Respostas:

224

O preenchimento de registros de data e hora no ObjectIds abrange consultas com base em datas incorporadas no ObjectId em grande detalhe.

Resumidamente no código JavaScript:

/* This function returns an ObjectId embedded with a given datetime */
/* Accepts both Date object and string input */

function objectIdWithTimestamp(timestamp) {
    /* Convert string date to Date object (otherwise assume timestamp is a date) */
    if (typeof(timestamp) == 'string') {
        timestamp = new Date(timestamp);
    }

    /* Convert date object to hex seconds since Unix epoch */
    var hexSeconds = Math.floor(timestamp/1000).toString(16);

    /* Create an ObjectId with that hex timestamp */
    var constructedObjectId = ObjectId(hexSeconds + "0000000000000000");

    return constructedObjectId
}


/* Find all documents created after midnight on May 25th, 1980 */
db.mycollection.find({ _id: { $gt: objectIdWithTimestamp('1980/05/25') } });
Leftium
fonte
29
Muito útil .. FYI, você pode salvar esta função no seu ~/.mongorc.jsarquivo para disponibilizá-lo quando o mongoshell for iniciado.
Stennie
1
Eu recebo o ReferenceError: ObjectId não está definido. Como faço para corrigir isso?
peter
3
Estou usando nodejs com mongodbnative. Corrigido o "erro não definido" incluindo var ObjectId = require ('mongodb'). ObjectID;
peter
1
Se você estiver usando o Mongoskin como eu: Altere ObjectId(hexSeconds + "0000000000000000");paradb.ObjectID.createFromHexString(hexSeconds + "0000000000000000");
Anders Östman
2
Ou, no Mongoose, substitua ObjectId()por: require('mongoose').Types.ObjectId()- onde require('mongoose')está sua instância do Mongoose inicializada / configurada.
toblerpwn
34

O uso da função embutida fornecida pelos drivers mongodb no Node.js permite consultar por qualquer carimbo de data / hora:

var timestamp = Date.now();
var objectId = ObjectID.createFromTime(timestamp / 1000);

Como alternativa, para procurar registros antes da hora atual, você pode simplesmente:

var objectId = new ObjectID(); // or ObjectId in the mongo shell

Fonte: http://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html

jksdua
fonte
3
Essa é a melhor / mais fácil maneira de criar um ObjectId a partir de um registro de data e hora em um ambiente javascript. Qual é o que o op pede ...
Anders Östman 16/01
34

Em pymongo, isso pode ser feito desta maneira:

import datetime
from bson.objectid import ObjectId
mins = 15
gen_time = datetime.datetime.today() - datetime.timedelta(mins=mins) 
dummy_id = ObjectId.from_datetime(gen_time)
result = list(db.coll.find({"_id": {"$gte": dummy_id}}))
Radtek
fonte
Observe que usar datetime.datetime.utcnow () ou datetime.datetime.today () retornará o mesmo resultado. A data e hora são tratadas para você.
Radtek 22/09
Como alternativa, sem usar pymongodependência: epoch_time_hex = format(int(time.time()), 'x') (não esqueça de acrescentar zeros à sua consulta) O pacote de hora foi usado ( import time).
VasiliNovikov
Perceba que o OP estava pedindo javascript, mas isso realmente me ajudou a simplificar meu código. Obrigado.
Fred S
14

Como os 4 primeiros bytes de um ObjectId representam um carimbo de data / hora , para consultar sua coleção cronologicamente, basta ordenar por ID:

# oldest first; use pymongo.DESCENDING for most recent first
items = db.your_collection.find().sort("_id", pymongo.ASCENDING)

Depois de obter os documentos, você pode obter o tempo de geração do ObjectId da seguinte maneira:

id = some_object_id
generation_time = id.generation_time
atp
fonte
1
Eu esperava algo que realmente permitisse fazer uma contagem de objetos criados antes de um certo tempo usando o tempo incorporado no ObjectId, mas parece que isso não seria acessível diretamente. Obrigado.
Zach
1
Você pode fazer isso, veja a resposta de Leftium.
atp
14

como encontrar o comando Find (esta data [2015-1-12] até esta data [2015-1-15]):

db.collection.find ({_ id: {$ gt: ObjectId (Math.floor ((nova data ('2015/1/12'))) / 1000) .toString (16) + "0000000000000000"), $ lt: ObjectId (Math.floor ((new Date ('2015/1/15'))) / 1000) .toString (16) + "0000000000000000")}}). Pretty ()

Conte o comando (nesta data [2015-1-12] até esta data [2015-1-15]):

db.collection.count ({_ id: {$ gt: ObjectId (Math.floor ((nova data ('2015/1/12'))) / 1000) .toString (16) + "0000000000000000"), $ lt: ObjectId (Math.floor ((nova data ('2015/1/15'))) / 1000) .toString (16) + "0000000000000000")}})

Remova o comando (nesta data [2015-1-12] até esta data [2015-1-15]):

db.collection.remove ({_ id: {$ gt: ObjectId (Math.floor ((nova data ('2015/1/12'))) / 1000) .toString (16) + "0000000000000000"), $ lt: ObjectId (Math.floor ((nova data ('2015/1/15'))) / 1000) .toString (16) + "0000000000000000")}})

Karthickkumar Nagaraj
fonte
10

Você pode usar a $convertfunção para extrair a data do ObjectId a partir da versão 4.0.

Algo como

$convert: { input: "$_id", to: "date" } 

Você pode consultar a data comparando entre a hora de início e término da data.

db.collectionname.find({
  "$expr":{
    "$and":[
      {"$gte":[{"$convert":{"input":"$_id","to":"date"}}, ISODate("2018-07-03T00:00:00.000Z")]},
      {"$lte":[{"$convert":{"input":"$_id","to":"date"}}, ISODate("2018-07-03T11:59:59.999Z")]}
    ]
  }
})

OU

Você pode usar taquigrafia $toDatepara conseguir o mesmo.

db.collectionname.find({
  "$expr":{
    "$and":[
      {"$gte":[{"$toDate":"$_id"}, ISODate("2018-07-03T00:00:00.000Z")]},
      {"$lte":[{"$toDate":"$_id"},ISODate("2018-07-03T11:59:59.999Z")]}
    ]
  }
})
Sagar Veeram
fonte
Só queria perguntar como usando $ convert OR $ toDate, o Mongo primeiro terá que converter e comparar se o documento está presente no intervalo ou não, mas no lado do cliente e apenas uma vez, então você não acha que a solução será mais eficiente do que isso? obrigado de qualquer maneira para dizer que estes dois operadores também existem :)
Sudhanshu Gaur
7

Para obter documentos com os últimos 60 dias da coleção mongo, usei a consulta abaixo no shell.

db.collection.find({_id: {$lt:new ObjectId( Math.floor(new Date(new Date()-1000*60*60*24*60).getTime()/1000).toString(16) + "0000000000000000" )}})
Murali
fonte
1
Use $ gt em vez de $ lt. Caso contrário, ele encontrará documentos inseridos antes (hoje - 60 dias).
yoooshi
1
@Vivek Os primeiros 4 bytes de ObjectId representam o número de segundos desde a época do unix (1970/1/1 00:00:00 UTC) e, como tal, você pode usá-lo com maior que ($ gt) e menor que ($ lt) para encontrar objetos que foram criados dentro de uma determinada janela.
John
5

Se você deseja fazer uma consulta de intervalo, pode fazê-lo como nesta postagem . Por exemplo, consultando para um dia específico (ou seja, 4 de abril de 2015):

> var objIdMin = ObjectId(Math.floor((new Date('2015/4/4'))/1000).toString(16) + "0000000000000000")
> var objIdMax = ObjectId(Math.floor((new Date('2015/4/5'))/1000).toString(16) + "0000000000000000")
> db.collection.find({_id:{$gt: objIdMin, $lt: objIdMax}}).pretty()
AbdelHady
fonte
2

Usando o MongoObjectID, você também deve encontrar os resultados conforme indicado abaixo

db.mycollection.find({ _id: { $gt: ObjectId("5217a543dd99a6d9e0f74702").getTimestamp().getTime()}});
Yogesh
fonte
3
sua instrução de consulta assume que se sabe o valor ObjectId para começar, o que nem sempre é o caso.
Dwight Spencer #
0

Nos trilhos, mongoidvocê pode consultar usando

  time = Time.utc(2010, 1, 1)
  time_id = ObjectId.from_time(time)
  collection.find({'_id' => {'$lt' => time_id}})
Lakhani Aliraza
fonte