използва за време на създаване на mongodb ObjectId

ObjectId, използван като ключ по подразбиране в документи на mongodb, има вградено времево клеймо (извикването на objectid.generation_time връща обект за дата и час). Така че е възможно да се използва това време на генериране, вместо да се запази отделно времево клеймо за създаване? Как ще можете ефективно да сортирате по време на създаване или заявка за последните N елемента, като използвате това вградено времево клеймо?


person kefeizhou    schedule 26.02.2011    source източник


Отговори (7)


Предполагам, че тъй като MongoDB ObjectId съдържа клеймо за време, можете да сортирате по „дата на създаване“, ако ще сортирате по objectId:

items.find.sort( [['_id', -1]] ) // get all items desc by created date.

И ако искате последните 30 създадени елемента, можете да използвате следната заявка:

items.find.sort( [['_id', -1]] ).limit(30) // get last 30 createad items 

Всъщност не съм сигурен, просто предполагам, че подреждането по _id трябва да работи, както е описано по-горе. Ще създам някои тестове по-късно.

Актуализация:

Да така е. Ако поръчате по _id, автоматично ще поръчате по _id създадена дата. Направих малък тест в c#, ​​mb някой се интересува от него:

  public class Item
  {
    [BsonId]
    public ObjectId Id { get; set; }

    public DateTime CreatedDate { get; set; }

    public int Index { get; set; }
  }



 [TestMethod]
 public void IdSortingTest()
 {
   var server = MongoServer.Create("mongodb://localhost:27020");
   var database = server.GetDatabase("tesdb");

   var collection = database.GetCollection("idSortTest");
   collection.RemoveAll();

   for (int i = 0; i <= 500; i++)
   {
     collection.Insert(new Item() { 
             Id = ObjectId.GenerateNewId(), 
             CreatedDate = DateTime.Now, 
             Index = i });
   }

   var cursor = collection.FindAllAs<Item>();
   cursor.SetSortOrder(SortBy.Descending("_id"));
   var itemsOrderedById = cursor.ToList();

   var cursor2 = collection.FindAllAs<Item>();
   cursor2.SetSortOrder(SortBy.Descending("CreatedDate"));
   var itemsOrderedCreatedDate = cursor.ToList();

   for (int i = 0; i <= 500; i++)
   {
     Assert.AreEqual(itemsOrderedById[i].Index, itemsOrderedCreatedDate[i].Index);
   }
}
person Andrew Orsich    schedule 26.02.2011
comment
Почти съм сигурен, че това е правилно само при вмъкване с помощта на един процес, bc. Mongo objectids се създават с помощта на нещо подобно на hilo последователности. По-конкретно: A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter - person Geert-Jan; 03.01.2013
comment
@Geert-Jan Тъй като времевият печат е най-значимата част от ObjectId, той ще сортира правилно през вмъквания от множество процеси (с точност до една секунда, ако приемем, че часовниците на процеса са добре синхронизирани). За да потвърдите това, вижте имплементирането на getTimeStamp() използва .slice(0,8). Това (0,8) избира най-значимите четири байта от ObjectId като клеймо за време. - person davetapley; 01.05.2013
comment
@dukedave: Разбира се, че ще работи, ако разделителната способност от 1 секунда е достатъчна. - person Geert-Jan; 01.05.2013

Да, можете да използвате поколение_време на BSON ObjectId за целите, които искате. Така,

db.collection.find().sort({ _id : -1 }).limit(10)

ще върне последните 10 създадени елемента. Въпреки това, тъй като вградените времеви отпечатъци имат точност от една секунда, множество елементи в рамките на всяка секунда се съхраняват в реда на тяхното създаване.

person user105991    schedule 02.03.2011

Кодът за преобразуване на DateTime в съответния му времеви печат с драйвера c# е както следва:

    public static ObjectId ToObjectId(this DateTime dateTime)
    {
        var timestamp = (int)(dateTime - BsonConstants.UnixEpoch).TotalSeconds;
        return new ObjectId(timestamp, 0, 0, 0);
    }

Повече информация тук: http://www.danharman.net/2011/10/26/mongodb-ninjitsu-using-objectid-as-a-timestamp/

person DanH    schedule 26.10.2011
comment
Конструкторът ObjectId вече има претоварване, което приема DateTime като клеймо за време, така че вашето преобразуване вече не е необходимо. Просто направете new ObjectId(dateTime, 0, 0, 0); - person Zaid Masud; 23.08.2013

От: http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-DocumentTimestamps

"сортирането на поле _id, което съхранява стойности на ObjectId, е приблизително еквивалентно на сортиране по време на създаване, въпреки че тази връзка не е строга със стойности на ObjectId, генерирани на множество системи в рамките на една секунда."

person wprl    schedule 05.04.2013

Вижте

http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-DocumentTimestamps

Вероятно осъществимо, но винаги бих предпочел да имам специално времево клеймо, вместо да разчитам на някои такива вътрешни елементи като времеви клеймо, вградено по някакъв начин в някакъв идентификатор на обект.

person Andreas Jung    schedule 26.02.2011
comment
Моля, обяснете защо е възможно, как можете ефективно да сортирате данни без btree индекс? - person kefeizhou; 26.02.2011
comment
Когато казвам вероятно изпълнимо, тогава не трябва да обяснявам всичко в подробности. Моля, проверете дадената връзка и сами ще откриете, че ObjectIds се увеличават само. И както казах: отидете със стандартно създадено поле. Не трябва да обяснявам всичко в дълбочина, което никога не бих направил. - person Andreas Jung; 26.02.2011
comment
съжалявам, но това изобщо не отговаря на въпроса - person kefeizhou; 26.02.2011

За заявка за проекти, създадени в рамките на 7 дни, използвам следния фрагмент:

db.getCollection('projects').find({
  $where: function() {
    // last 7 days
    return Date.now() - this._id.getTimestamp() < (7 * 24 * 60 * 60 * 1000)
  }
}).sort({
  '_id': -1
})

и ако искате да получите елементи с определени полета:

db.getCollection('projects').find({
  $where: function() {
    // last 7 days
    return Date.now() - this._id.getTimestamp() < (7 * 24 * 60 * 60 * 1000)
  }
}).sort({
  '_id': -1
}).toArray().map(function(item) {
  var res = {};
  res['Project Name'] = item.config.label;
  res['Author'] = item.author;
  res['Created At'] = item._id.getTimestamp().toLocaleDateString();
  res['Last Modified Date'] = item.config.lastModifDate.toLocaleString();
  return res;
});

ще върне нещо подобно:

[{
  "Project Name": "Newsletter",
  "Author": "larry.chen",
  "Created At": "Thursday, January 19, 2017",
  "Last Modified Date": "Thursday, January 19, 2017 17:05:40"
}...]

PS: Софтуерът, който използвам за свързване с MongoDB, е Robo 3T

Надявам се това да ви помогне.

person Chen Dachao    schedule 19.01.2017
comment
не че знам много от това, но предложеното от вас решение ми изглежда безумно неефективно. какво правиш, когато имаш 10kk записи? трябва ли функцията $where да се приложи към всеки един от тях? - person phil294; 01.12.2018
comment
Съжалявам, че не те разбрах - person Chen Dachao; 02.12.2018

За тези, които искат наистина да използват ObjectId за datetime, а не само да разчитат на факта, че ObjectId винаги се увеличават с времето и следователно могат да се използват за подреждане на документи чрез индиректно време на създаване, тогава ето как:

Човек може да създаде свои критерии за филтриране, за да върне документи, чиито идентификатори са направени в някакъв диапазон от дата и време (в Python), като направи фиктивно ObjectID.from_datetime() така:

# gets docs which were created in last 5 minutes
resp = await collection.update_one({'_id': {'$gte': ObjectId.from_datetime(datetime.utcnow() - timedelta(minutes=5))}},
person hamx0r    schedule 25.02.2021