ObjectId
, използван като ключ по подразбиране в документи на mongodb, има вградено времево клеймо (извикването на objectid.generation_time връща обект за дата и час). Така че е възможно да се използва това време на генериране, вместо да се запази отделно времево клеймо за създаване? Как ще можете ефективно да сортирате по време на създаване или заявка за последните N елемента, като използвате това вградено времево клеймо?
използва за време на създаване на mongodb ObjectId
Отговори (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);
}
}
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
ObjectId
, той ще сортира правилно през вмъквания от множество процеси (с точност до една секунда, ако приемем, че часовниците на процеса са добре синхронизирани). За да потвърдите това, вижте имплементирането на getTimeStamp()
използва .slice(0,8)
. Това (0,8)
избира най-значимите четири байта от ObjectId
като клеймо за време.
- person davetapley; 01.05.2013
Да, можете да използвате поколение_време на BSON ObjectId за целите, които искате. Така,
db.collection.find().sort({ _id : -1 }).limit(10)
ще върне последните 10 създадени елемента. Въпреки това, тъй като вградените времеви отпечатъци имат точност от една секунда, множество елементи в рамките на всяка секунда се съхраняват в реда на тяхното създаване.
Кодът за преобразуване на 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/
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, генерирани на множество системи в рамките на една секунда."
Вижте
http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-DocumentTimestamps
Вероятно осъществимо, но винаги бих предпочел да имам специално времево клеймо, вместо да разчитам на някои такива вътрешни елементи като времеви клеймо, вградено по някакъв начин в някакъв идентификатор на обект.
За заявка за проекти, създадени в рамките на 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
Надявам се това да ви помогне.
$where
да се приложи към всеки един от тях?
- person phil294; 01.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))}},