Posso interrogare MongoDB ObjectId per data?


Risposte:


224

La suddivisione dei timestamp in ObjectIds copre in modo dettagliato le query basate sulle date incorporate nell'IdId.

Brevemente nel codice 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') } });

29
Molto utile .. Cordiali saluti, è possibile salvare questa funzione nel ~/.mongorc.jsfile per renderlo disponibile all'avvio della mongoshell.
Stennie,

1
Ottengo ReferenceError: ObjectId non è definito. Come lo risolvo?
Pietro,

3
Sto usando nodejs con mongodbnative. Risolto l'errore "non definito" includendo var ObjectId = require ('mongodb'). ObjectID;
Pietro,

1
Se stai usando Mongoskin come faccio io: ObjectId(hexSeconds + "0000000000000000");passa adb.ObjectID.createFromHexString(hexSeconds + "0000000000000000");
Anders Östman il

2
Oppure, in Mongoose, sostituire ObjectId()con: require('mongoose').Types.ObjectId()- dove si require('mongoose')trova l'istanza Mongoose inizializzata / configurata.
Toblerpwn,

34

L'uso della funzione integrata fornita dai driver mongodb in Node.js consente di eseguire query in base a qualsiasi data e ora:

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

In alternativa, per cercare record prima dell'ora corrente, puoi semplicemente fare:

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

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


3
Questo è il modo migliore / più semplice per creare un ObjectId da un timestamp in un ambiente javascript. Questo è ciò che richiede l'operazione ...
Anders Östman,

34

In pymongo, può essere fatto in questo modo:

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

La nota che utilizza datetime.datetime.utcnow () o datetime.datetime.today () restituirà lo stesso risultato. Il datetime è gestito per te.
Radtek,

In alternativa, senza usare la pymongodipendenza: epoch_time_hex = format(int(time.time()), 'x') (non dimenticare di aggiungere zero per la tua query) Il pacchetto time è stato usato ( import time).
VasiliNovikov,

Realizzare che l'OP stava chiedendo javascript, ma questo mi ha davvero aiutato a semplificare il mio codice. Grazie.
Fred S

14

Poiché i primi 4 byte di un ObjectId rappresentano un timestamp , per eseguire una query cronologicamente sulla tua raccolta, ordina semplicemente per id:

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

Dopo aver ottenuto i documenti, puoi ottenere il tempo di generazione dell'ObjectId in questo modo:

id = some_object_id
generation_time = id.generation_time

1
Speravo in qualcosa che potesse effettivamente consentire di fare cose come ottenere un conteggio di oggetti creati prima di un certo tempo usando il tempo incorporato nell'IdeaId, ma sembra che non sia direttamente accessibile. Grazie.
Zach,

1
Puoi farlo, guarda la risposta di Leftium.
atp

14

come trovare Trova il comando (questa data [2015-1-12] a questa data [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 ()

Conta il comando (questa data [2015-1-12] fino a questa data [2015-1-15]):

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

Rimuovi il comando (questa data [2015-1-12] a questa data [2015-1-15]):

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


10

È possibile utilizzare la $convertfunzione per estrarre la data da ObjectId a partire dalla versione 4.0.

Qualcosa di simile a

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

È possibile eseguire una query sulla data confrontando tra ora di inizio e fine per la 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")]}
    ]
  }
})

O

È possibile utilizzare la scorciatoia $toDateper ottenere lo stesso.

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

Volevo solo chiedere come usando $ convert OR $ toDate, Mongo dovrà prima convertire e poi confrontare se il documento è presente nell'intervallo o meno, ma se dovessi usare l'approccio della risposta accettata, convertire la data in un ObjectId dovrei solo fare sul lato client e solo una volta, quindi non pensi che la soluzione sarà più efficiente di così? grazie comunque per aver detto che esistono anche questi due operatori :)
Sudhanshu Gaur

7

Per ottenere i documenti degli ultimi 60 giorni nella raccolta di mongo ho usato di seguito la query nella shell.

db.collection.find({_id: {$lt:new ObjectId( Math.floor(new Date(new Date()-1000*60*60*24*60).getTime()/1000).toString(16) + "0000000000000000" )}})

1
Usa $ gt invece di $ lt. Altrimenti, trova i documenti inseriti prima (oggi-60 giorni).
Yoooshi,

1
@Vivek I primi 4 byte di ObjectId rappresentano il numero di secondi dall'epoca di unix (1970/1/1 00:00:00 UTC), e come tale puoi usarlo con maggiore di ($ gt) e minore di ($ lt) per trovare oggetti creati all'interno di una determinata finestra.
John

5

Se vuoi fare una query sul range, puoi farlo come in questo post . Ad esempio, per una query per un giorno specifico (ovvero il 4 aprile 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()


2

Utilizzando MongoObjectID dovresti trovare anche i risultati come indicato di seguito

db.mycollection.find({ _id: { $gt: ObjectId("5217a543dd99a6d9e0f74702").getTimestamp().getTime()}});

3
l'istruzione della query presuppone che si conosca il valore ObjectId per cominciare, che non è sempre il caso.
Dwight Spencer,

0

In rotaie mongoidè possibile eseguire query utilizzando

  time = Time.utc(2010, 1, 1)
  time_id = ObjectId.from_time(time)
  collection.find({'_id' => {'$lt' => time_id}})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.