Чи можна запитувати MongoDB ObjectId за датою?


145

Я знаю, що ObjectIds містять дату, коли вони були створені. Чи є спосіб запитувати цей аспект ObjectId?



Я отримав рішення на steveridout.github.io/mongo-object-time
bpedroso

Відповіді:


224

Popping Timestamps в ObjectIds охоплює запити на основі дат, вкладених у ObjectId дуже детально.

Коротко в коді 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
Дуже зручно .. FYI, ви можете зберегти цю функцію у вашому ~/.mongorc.jsфайлі, щоб мати її доступною при mongoзапуску оболонки.
Стенні

1
Я отримую ReferenceError: ObjectId не визначено. Як я можу це виправити?
пітер

3
Я використовую nodejs з mongodbnative. Виправлена ​​"не визначена помилка", включивши var ObjectId = requ ('mongodb').
пітер

1
Якщо ви використовуєте Монгоскін, як я: Змініть ObjectId(hexSeconds + "0000000000000000");наdb.ObjectID.createFromHexString(hexSeconds + "0000000000000000");
Anders Östman

2
Або в Mongoose замініть ObjectId()на: require('mongoose').Types.ObjectId()- де require('mongoose')ваш ініціалізований / налаштований екземпляр Mongoose.
toblerpwn

34

Використання вбудованої функції, наданої драйверами mongodb в Node.js, дозволяє здійснювати запит будь-якої часової позначки:

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

Крім того, для пошуку записів до поточного часу, ви можете просто зробити:

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

Джерело: http://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html


3
Це найкращий / найпростіший спосіб створити ObjectId з часової позначки в jav-середовищі. Що про це вимагає оп ...
Андерс Остман

34

У pymongo, це можна зробити так:

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

Зауважте, що використання datetime.datetime.utcnow () або datetime.datetime.today () поверне той самий результат. Час дати обробляється для вас.
radtek

Крім того, без використання pymongoзалежності: epoch_time_hex = format(int(time.time()), 'x') (не забудьте додати нулі для вашого запиту) Пакет часу використовувався ( import time).
ВасильНовіков

Зрозумійте, що ОП просив javascript, але це дійсно допомогло мені спростити код. Дякую.
Фред S

14

Оскільки перші 4 байти ObjectId являють собою часову позначку , для запиту колекції хронологічно просто впорядкуйте за id:

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

Отримавши документи, ви можете отримати час генерації ObjectId таким чином:

id = some_object_id
generation_time = id.generation_time

1
Я сподівався на щось, що насправді дозволить робити такі речі, як отримати кількість об'єктів, створених до певного часу, використовуючи час, вбудований в ObjectId, але, схоже, це не було б безпосередньо доступне. Дякую.
Зак

1
Ви можете це зробити, подивіться на відповідь Лефтія.
atp

13

як знайти Знайти команду (дату [2015-1-12] до цієї дати [2015-1-15]):

db.collection.find ({_ id: {$ gt: ObjectId (Math.floor ((нова дата ('2015/1/12'))) / 1000) .toString (16) + "0000000000000000"), $ lt: ObjectId (Math.floor ((нова дата ('2015/1/15')) / 1000) .toString (16) + "0000000000000000")}}). Досить ()

Відрахуйте команду (дату [2015-1-12] до цієї дати [2015-1-15]):

db.collection.count ({_ id: {$ gt: ObjectId (Math.floor ((нова дата ('2015/1/12')) / 1000) .toString (16) + "0000000000000000"), $ lt: ObjectId (Math.floor ((нова дата ('2015/1/15')) / 1000) .toString (16) + "0000000000000000")}})

Видаліть команду (ця дата [2015-1-12] до цієї дати [2015-1-15]):

db.collection.remove ({_ id: {$ gt: ObjectId (Math.floor ((нова дата ('2015/1/12'))) / 1000) .toString (16) + "0000000000000000"), $ lt: ObjectId (Math.floor ((нова дата ('2015/1/15')) / 1000) .toString (16) + "0000000000000000")}})


10

Ви можете використовувати $convertфункцію для вилучення дати з ObjectId, починаючи з версії 4.0.

Щось на зразок

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

Ви можете здійснювати запит на дату, порівнюючи час початку та закінчення дати.

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

АБО

Ви можете скористатися скороченням, $toDateщоб досягти того ж.

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

Просто хотів запитати, як використовується $ convert АБО $ toDate, спочатку Монго доведеться конвертувати, а потім порівнювати, чи присутній документ у діапазоні чи ні, але якщо я використовував би прийнятий відповідь, тоді перетворення дати в ObjectId я повинен був би зробити тільки на стороні клієнта і лише один раз. Тож ви не вважаєте, що рішення буде ефективнішим за це? все одно дякую за те, що ви сказали, що ці два оператори також існують :)
Sudhanshu Gaur

7

Для отримання останніх 60 днів документів у колекції монго я використовував нижче запит у оболонці.

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

1
Використовуйте $ gt замість $ lt. В іншому випадку він знаходить документи, вставлені раніше (сьогодні-60 днів).
yoooshi

1
@Vivek Перші 4 байти ObjectId представляють кількість секунд з часу епохи unix (1970/1/1 00:00:00 UTC), і як такий ви можете використовувати його з більшим ніж ($ gt) і менше ($ lt) для пошуку об’єктів, створених у певному вікні.
Джон

5

Якщо ви хочете зробити запит про діапазон, ви можете зробити це, як у цій публікації . Наприклад, запит на певний день (тобто 4 квітня 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

Використовуючи MongoObjectID, ви також повинні знайти результати, наведені нижче

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

3
ваш випадок запиту припускає, що ви знаєте значення ObjectId для початку, яке не завжди так.
Дуайт Спенсер

0

У рейках mongoidможна здійснити запит, використовуючи

  time = Time.utc(2010, 1, 1)
  time_id = ObjectId.from_time(time)
  collection.find({'_id' => {'$lt' => time_id}})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.