Kann ich MongoDB ObjectId nach Datum abfragen?


Antworten:


224

Das Einfügen von Zeitstempeln in ObjectIds behandelt Abfragen, die auf in der ObjectId eingebetteten Daten basieren, ausführlich.

Kurz im JavaScript-Code:

/* 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
Sehr praktisch. Zu Ihrer Information, Sie können diese Funktion in Ihrer ~/.mongorc.jsDatei speichern, damit sie beim mongoStart der Shell verfügbar ist.
Stennie

1
Ich erhalte ReferenceError: ObjectId ist nicht definiert. Wie behebe ich das?
Peter

3
Ich benutze NodeJs mit Mongodbnative. Der "nicht definierte Fehler" wurde behoben, indem var ObjectId = require ('mongodb') eingeschlossen wurde. ObjectID;
Peter

1
Wenn Sie Mongoskin wie ich verwenden: Wechseln Sie ObjectId(hexSeconds + "0000000000000000");zudb.ObjectID.createFromHexString(hexSeconds + "0000000000000000");
Anders Östman

2
Oder ersetzen Sie in Mongoose durch ObjectId(): require('mongoose').Types.ObjectId()- Wo require('mongoose')befindet sich Ihre initialisierte / konfigurierte Mongoose-Instanz?
toblerpwn

34

Mit der integrierten Funktion, die von Mongodb-Treibern in Node.js bereitgestellt wird, können Sie nach einem beliebigen Zeitstempel abfragen:

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

Um vor der aktuellen Zeit nach Datensätzen zu suchen, können Sie alternativ einfach Folgendes tun:

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

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


3
Dies ist der beste / einfachste Weg, um eine ObjectId aus einem Zeitstempel in einer Javascript-Umgebung zu erstellen. Welches ist, was die Operation verlangt ...
Anders Östman

34

In pymongokann es so gemacht werden:

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

Beachten Sie, dass die Verwendung von datetime.datetime.utcnow () oder datetime.datetime.today () dasselbe Ergebnis zurückgibt. Die datetime wird für Sie behandelt.
Radtek

Alternativ, ohne pymongoAbhängigkeit zu verwenden: epoch_time_hex = format(int(time.time()), 'x') (Vergessen Sie nicht, Nullen für Ihre Abfrage anzuhängen.) Das Zeitpaket wurde verwendet ( import time).
VasiliNovikov

Ich habe festgestellt, dass das OP nach Javascript gefragt hat, aber das hat mir wirklich geholfen, meinen Code zu vereinfachen. Vielen Dank.
Fred S

14

Da die ersten 4 Bytes einer ObjectId einen Zeitstempel darstellen , müssen Sie Ihre Sammlung einfach nach ID sortieren , um Ihre Sammlung chronologisch abzufragen:

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

Nachdem Sie die Dokumente erhalten, können Sie den von ObjectId erhalten Generationszeit etwa so:

id = some_object_id
generation_time = id.generation_time

1
Ich hatte auf etwas gehofft, das es tatsächlich ermöglicht, Dinge wie eine Anzahl von Objekten zu erstellen, die vor einer bestimmten Zeit unter Verwendung der in der ObjectId eingebetteten Zeit erstellt wurden, aber es scheint, dass dies nicht direkt zugänglich wäre. Vielen Dank.
Zach

1
Sie können das tun, schauen Sie sich Leftiums Antwort an.
atp

13

So finden Sie Find the Command (dieses Datum [2015-1-12] bis zu diesem Datum [2015-1-15]):

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

Zählen Sie den Befehl (dieses Datum [2015-1-12] bis zu diesem Datum [2015-1-15]):

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

Entfernen Sie den Befehl (dieses Datum [2015-1-12] bis zu diesem Datum [2015-1-15]):

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


10

Mit der $convertFunktion können Sie das Datum ab der Version 4.0 aus ObjectId extrahieren.

Etwas wie

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

Sie können das Datum abfragen, indem Sie die Start- und Endzeit für das Datum vergleichen.

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

ODER

Sie können die Kurzschrift verwenden $toDate, um dasselbe zu erreichen.

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

Ich wollte nur fragen, ob ich $ convert OR $ toDate verwenden möchte. Mongo muss zuerst konvertieren und dann vergleichen, ob das Dokument im Bereich vorhanden ist oder nicht. Wenn ich jedoch den Ansatz einer akzeptierten Antwort verwenden würde, müsste ich nur das Datum in eine ObjectId konvertieren Auf Kundenseite und nur einmal. Glauben Sie nicht, dass diese Lösung effizienter sein wird?
Trotzdem

7

Um die letzten 60 Tage alten Dokumente in der Mongo-Sammlung zu erhalten, habe ich die folgende Abfrage in der Shell verwendet.

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

1
Verwenden Sie $ gt anstelle von $ lt. Andernfalls werden zuvor eingefügte Dokumente gefunden (heute - 60 Tage).
Yoooshi

1
@Vivek Die ersten 4 Bytes von ObjectId geben die Anzahl der Sekunden seit der Unix-Epoche (1970/1/1 00:00:00 UTC) an. Daher können Sie sie mit mehr als ($ gt) und weniger als ($) verwenden lt) um Objekte zu finden, die in einem bestimmten Fenster erstellt wurden.
John

5

Wenn Sie eine Bereichsabfrage durchführen möchten, können Sie dies wie in diesem Beitrag tun . Zum Beispiel Abfragen für einen bestimmten Tag (dh 4. April 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

Mit MongoObjectID sollten Sie auch die unten angegebenen Ergebnisse finden

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

3
Ihre Abfrageanweisung setzt voraus, dass man zunächst den ObjectId-Wert kennt, was nicht immer der Fall ist.
Dwight Spencer

0

In Schienen können mongoidSie mit abfragen

  time = Time.utc(2010, 1, 1)
  time_id = ObjectId.from_time(time)
  collection.find({'_id' => {'$lt' => time_id}})
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.