Bisakah saya meminta ObjectId MongoDB berdasarkan tanggal?

Jawaban:

224

Popping Stempel Waktu ke ObjectIds mencakup kueri berdasarkan tanggal yang disematkan di ObjectId dengan sangat rinci.

Secara singkat dalam kode 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
sumber
29
Sangat berguna .. FYI, Anda dapat menyimpan fungsi ini di ~/.mongorc.jsfile Anda agar tersedia saat mongoshell dijalankan.
Stennie
1
Saya mendapatkan ReferenceError: ObjectId tidak didefinisikan. Bagaimana cara memperbaikinya?
peter
3
Saya menggunakan nodejs dengan mongodbnative. Memperbaiki "not defined error" dengan memasukkan var ObjectId = require ('mongodb'). ObjectID;
peter
1
Jika Anda menggunakan Mongoskin seperti yang saya lakukan: Ubah ObjectId(hexSeconds + "0000000000000000");kedb.ObjectID.createFromHexString(hexSeconds + "0000000000000000");
Anders Östman
2
Atau, dalam Mongoose, ganti ObjectId()dengan: require('mongoose').Types.ObjectId()- di mana require('mongoose')instance Mongoose yang diinisialisasi / dikonfigurasikan.
toblerpwn
34

Menggunakan fungsi inbuilt yang disediakan oleh driver mongodb di dalam Node.js memungkinkan Anda melakukan kueri dengan cap waktu apa pun:

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

Atau, untuk mencari catatan sebelum waktu saat ini, Anda cukup melakukan:

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

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

jksdua
sumber
3
Ini adalah cara terbaik / termudah untuk membuat ObjectId dari cap waktu di javascript env. Itulah yang diminta oleh op ...
Anders Östman
34

Di pymongo, dapat dilakukan dengan cara ini:

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
sumber
Catatan menggunakan datetime.datetime.utcnow () atau datetime.datetime.today () akan mengembalikan hasil yang sama. Datetime ditangani untuk Anda.
radtek
Atau, tanpa menggunakan pymongodependensi: epoch_time_hex = format(int(time.time()), 'x') (jangan lupa menambahkan angka nol untuk kueri Anda) Paket waktu digunakan ( import time).
VasiliNovikov
Menyadari OP meminta javascript, tetapi ini benar-benar membantu saya menyederhanakan kode saya. Terima kasih.
Fred S
14

Karena 4 byte pertama ObjectId mewakili cap waktu , untuk meminta koleksi Anda secara kronologis, cukup pesan dengan id:

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

Setelah Anda mendapatkan dokumen, Anda bisa mendapatkan ObjectId ini waktu generasi seperti:

id = some_object_id
generation_time = id.generation_time
atp
sumber
1
Saya berharap untuk sesuatu yang benar-benar memungkinkan untuk melakukan hal-hal seperti mendapatkan hitungan objek yang dibuat sebelum waktu tertentu menggunakan waktu yang tertanam dalam ObjectId, tetapi sepertinya itu tidak dapat diakses secara langsung. Terima kasih.
Zach
1
Anda dapat melakukannya, lihat jawaban Leftium.
atp
14

bagaimana menemukan Find the Command (tanggal ini [2015-1-12] hingga Tanggal ini [2015-1-15]):

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

Hitung Perintah (tanggal ini [2015-1-12] hingga Tanggal ini [2015-1-15]):

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

Hapus Perintah (tanggal ini [2015-1-12] hingga Tanggal ini [2015-1-15]):

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

Karthickkumar Nagaraj
sumber
10

Anda bisa menggunakan $convertfungsi untuk mengekstrak tanggal dari ObjectId mulai versi 4.0.

Sesuatu seperti

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

Anda dapat meminta tanggal membandingkan antara waktu mulai dan waktu berakhir untuk tanggal.

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

ATAU

Anda dapat menggunakan singkatan $toDateuntuk mencapai hal yang sama.

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
sumber
Hanya ingin bertanya menggunakan $ convert ATAU $ toDate, Mongo pertama-tama harus mengonversi dan kemudian membandingkan apakah doc ada dalam kisaran atau tidak, tetapi Jika saya akan menggunakan pendekatan jawaban yang diterima kemudian mengonversi tanggal ke ObjectId saya hanya perlu melakukan di sisi klien dan hanya sekali, Jadi jangan Anda berpikir solusi itu akan lebih efisien daripada ini? terima kasih karena sudah memberi tahu bahwa kedua operator ini juga ada :)
Sudhanshu Gaur
7

Untuk mendapatkan dokumen-dokumen lama 60 hari terakhir dalam koleksi mongo saya gunakan di bawah permintaan dalam 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
sumber
1
Gunakan $ gt, bukan $ lt. Kalau tidak, ia menemukan dokumen yang disisipkan sebelumnya (hari ini-60 hari).
yoooshi
1
@Vivek 4 byte pertama dari ObjectId mewakili jumlah detik sejak zaman unix (1970/1/1 00:00:00 UTC), dan karenanya Anda dapat menggunakannya dengan lebih dari ($ gt) dan kurang dari ($ lt) untuk menemukan objek yang dibuat dalam jendela tertentu.
John
5

Jika Anda ingin membuat kueri rentang, Anda bisa melakukannya seperti di posting ini . Misalnya permintaan untuk hari tertentu (mis. 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()
AbdelHady
sumber
2

Menggunakan MongoObjectID Anda juga harus menemukan hasil seperti yang diberikan di bawah ini

db.mycollection.find({ _id: { $gt: ObjectId("5217a543dd99a6d9e0f74702").getTimestamp().getTime()}});
Yogesh
sumber
3
pernyataan kueri Anda mengasumsikan orang tahu nilai ObjectId untuk memulai dengan yang tidak selalu terjadi.
Dwight Spencer
0

Di rel, mongoidAnda dapat meminta menggunakan

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