I have the following code. The EnsureIndexes is called by the constructor to make sure that a TTL index has been created on the _expireAt field. Then when a document is inserted by calling the AddOrUpdateItem method, it adds a future date to the _expireAt field. However, that date passes and the document never expires. What am I doing wrong?
private void EnsureIndexes()
{
if (!_indexChecked)
{
// TTL index
var tsk =
MongoCollection.Indexes.CreateOneAsync(Builders<BsonDocument>.IndexKeys.Ascending("_expireAt"),
new CreateIndexOptions() { ExpireAfter = TimeSpan.FromSeconds(0) });
tsk.Wait();
_indexChecked = true;
}
}
public void AddOrUpdateItem(string key, TValue value, TimeSpan timeout)
{
var json = value.ToJson();
dynamic jObject = JObject.Parse(json);
jObject._expireAt = DateTime.UtcNow.Add(timeout);
json = jObject.ToString();
var replacementDocument = BsonSerializer.Deserialize<BsonDocument>(json);
var filter = new BsonDocument("_id", key);
var options = new UpdateOptions {IsUpsert = true};
var tsk = MongoCollection.ReplaceOneAsync(filter, replacementDocument, options);
try
{
tsk.Wait();
}
catch (AggregateException ex)
{
// TODO: Log
throw;
}
}
The following is returned with the command to getIndices on the Mongo collection.
> db.Users.getIndices()
[ { "v" : 1, "key" : { "_id" : 1 }, "name" : "id", "ns" : "AuditDemo.Users" }, { "v" : 1, "key" : { "_expireAt" : 1 }, "name" : "_expireAt_1", "ns" : "AuditDemo.Users", "expireAfterSeconds" : 0 } ] >
In my AddOrUpdateItem method I first serialize a generic type to json in order to be able to add a dynamic element for the expireAt. Then I use the BsonSerializer to deserialize this modified json into a BsonDocument. At this point, does the BsonDocument translate the datetime json string to a BSon date type in order for the TTL index to work?
Result from the findOne command
> db.Users.findOne({"_expireAt":{$exists: true}})
{ "_id" : "0", "UserGuid" : { "Value" : "054f6141-e655-41dd-a9d5-39382d3360ab" }, "UserName" : null, "FirstName" : { "Value" : "JORDAN" }, "LastName" : { "Value" : "ACEVEDO" }, "Email" : { "Value" : "JORDAN.ACEVEDO@fake.com" }, "__typ" : "AuditDemo.ConsoleApplication.Models.Wss.UserInfo, ConsoleTest App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "_expireAt" : "2015-05-31T10:23:15.8979321Z" } >
OK, I figured out how to correct this date issue. The date time string that I got from JSON.Net, was not getting stored a BSON date object. So I had to call the BsonDateTime.create() method on the deserialized BsonDocument property and force it to be a BSON date. When it gets stored in the correct data type, the TTL index works as expected.
DateTime expiresDate = new DateTime(DateTime.UtcNow.Ticks, DateTimeKind.Utc).Add(timeout);
var replacementDocument = BsonSerializer.Deserialize<BsonDocument>(json);
replacementDocument["_expireAt"] = BsonDateTime.Create(expiresDate);
var filter = new BsonDocument("_id", key);
var options = new UpdateOptions {IsUpsert = true};
var tsk = MongoCollection.ReplaceOneAsync(filter, replacementDocument, options);