¿Puedo consultar MongoDB ObjectId por fecha?

Respuestas:

224

Hacer estallar marcas de tiempo en ObjectIds cubre consultas basadas en fechas incrustadas en ObjectId con gran detalle.

Brevemente en 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
fuente
29
Muy útil. Para su información, puede guardar esta función en su ~/.mongorc.jsarchivo para tenerla disponible cuando se mongoinicie el shell.
Stennie
1
Obtengo ReferenceError: ObjectId no está definido. ¿Cómo arreglo eso?
Peter
3
Estoy usando nodejs con mongodbnative. Se corrigió el "error no definido" al incluir var ObjectId = require ('mongodb'). ObjectID;
Peter
1
Si está usando Mongoskin como yo: Cambie ObjectId(hexSeconds + "0000000000000000");adb.ObjectID.createFromHexString(hexSeconds + "0000000000000000");
Anders Östman
2
O, en Mongoose, reemplácelo ObjectId()con: require('mongoose').Types.ObjectId()- donde require('mongoose')está su instancia de Mongoose inicializada / configurada.
toblerpwn
34

El uso de la función incorporada proporcionada por los controladores mongodb en Node.js le permite consultar por cualquier marca de tiempo:

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

Alternativamente, para buscar registros antes de la hora actual, simplemente puede hacer:

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

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

jksdua
fuente
3
Esta es la forma mejor / más fácil de crear un ObjectId a partir de una marca de tiempo en un entorno JavaScript. Que es lo que pide el
operador
34

En pymongo, se puede hacer de esta manera:

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
fuente
Tenga en cuenta que usar datetime.datetime.utcnow () o datetime.datetime.today () devolverá el mismo resultado. La fecha y hora se maneja por usted.
radtek
Alternativamente, sin usar pymongodependencia: epoch_time_hex = format(int(time.time()), 'x') (no olvide agregar ceros para su consulta) Se utilizó el paquete de tiempo ( import time).
VasiliNovikov
Date cuenta de que OP estaba pidiendo JavaScript, pero esto realmente me ayudó a simplificar mi código. Gracias.
Fred S
14

Dado que los primeros 4 bytes de un ObjectId representan una marca de tiempo , para consultar su colección cronológicamente, simplemente ordene por id:

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

Después de obtener los documentos, puede obtener el tiempo de generación del ObjectId de la siguiente manera:

id = some_object_id
generation_time = id.generation_time
atp
fuente
1
Esperaba algo que realmente permitiera hacer cosas como obtener un recuento de objetos creados antes de un cierto tiempo usando el tiempo incrustado en el ObjectId, pero parece que eso no sería directamente accesible. Gracias.
Zach
1
Puedes hacer eso, mira la respuesta de Leftium.
atp
14

cómo encontrar Buscar el comando (esta fecha [2015-1-12] a esta fecha [2015-1-15]):

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

Cuente el comando (esta fecha [2015-1-12] a esta fecha [2015-1-15]):

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

Elimine el comando (esta fecha [2015-1-12] a esta fecha [2015-1-15]):

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

Karthickkumar Nagaraj
fuente
10

Puede usar la $convertfunción para extraer la fecha de ObjectId a partir de la versión 4.0.

Algo como

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

Puede consultar la fecha comparando entre la hora de inicio y finalización de la fecha.

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")]}
    ]
  }
})

O

Puedes usar la taquigrafía $toDatepara lograr lo mismo.

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
fuente
Solo quería preguntar como usar $ convert OR $ toDate, Mongo primero tendrá que convertir y luego comparar si el documento está presente en el rango o no, pero si usaría el enfoque de respuesta aceptada y luego convertir la fecha a un ObjectId solo tendría que hacer del lado del cliente y solo una vez, ¿no cree que esa solución será más eficiente que esta? gracias de todos modos por decir que estos dos operadores también existen :)
Sudhanshu Gaur
7

Para obtener los documentos de los últimos 60 días en la colección mongo, utilicé la siguiente consulta en 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
fuente
1
Use $ gt en lugar de $ lt. De lo contrario, encuentra documentos insertados antes (hoy-60 días).
yoooshi
1
@Vivek Los primeros 4 bytes de ObjectId representan el número de segundos desde la época de Unix (1970/1/1 00:00:00 UTC), y como tal, puede usarlo con mayor que ($ gt) y menor que ($ lt) para encontrar objetos que se crearon dentro de una determinada ventana.
John
5

Si desea realizar una consulta de rango, puede hacerlo como en esta publicación . Por ejemplo, para consultar un día específico (es decir, 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
fuente
2

Usando MongoObjectID también debería encontrar los resultados que se muestran a continuación

db.mycollection.find({ _id: { $gt: ObjectId("5217a543dd99a6d9e0f74702").getTimestamp().getTime()}});
Yogesh
fuente
3
su declaración de consulta asume que uno conoce el valor ObjectId para comenzar, que no siempre es el caso.
Dwight Spencer
0

En rails mongoidpuedes consultar usando

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