[英]In C#, using the Mongo Driver, how can I set a "last modified field"?
Because Personio's API won't tell me when employees are created or modified which creates scalability issues for us, I'm creating a cache where I can store the Personio with metadata including whether/when it has been modified.因为 Personio 的 API 不会告诉我何时创建或修改了员工,这给我们带来了可扩展性问题,所以我正在创建一个缓存,我可以在其中存储 Personio 的元数据,包括是否/何时修改。
I've already learned from @Charchit Kapoor I should be able to use $addFields with $function to populate a "lastModified" value, so now I'm trying to make this work within my C# application.我已经从@Charchit Kapoor 了解到,我应该能够使用 $addFields 和 $function 来填充“lastModified”值,所以现在我正试图在我的 C# 应用程序中完成这项工作。
I've created the following Save
method:我创建了以下Save
方法:
public Task<UpdateResult[]> Save(List<StoredDynamicRecord> personioRecords, CancellationToken cancellationToken)
{
IMongoCollection<StoredDynamicRecord> collection = GetCollection<StoredDynamicRecord>();
IEnumerable<Task<UpdateResult>> updateResultTasks
= personioRecords.Select(personioRecord =>
{
string id = (string)personioRecord.AttributesByName["id"].Value;
personioRecord.CacheId = string.IsNullOrEmpty(id)
? ObjectId.GenerateNewId()
.ToString()
: id;
personioRecord.SyncTimestamp = DateTime.UtcNow;
return collection.UpdateOneAsync(
filter: Builders<StoredDynamicRecord>.Filter.Eq(x => x.CacheId, personioRecord.CacheId),
update: new EmptyPipelineDefinition<StoredDynamicRecord>()
.AppendStage<StoredDynamicRecord, StoredDynamicRecord, StoredDynamicRecord>(
@$"{{ ""$replaceWith"":
{personioRecord.ToBsonDocument()}
}}"
)
.AppendStage<StoredDynamicRecord, StoredDynamicRecord, StoredDynamicRecord>(
@$"{{ ""$addFields"": {{ ""_lastModified"": {{ ""$function"": {{
""lang"": ""js"",
""args"": [
""$ROOT"",
{{
""key"": 1,
""data"": ""somedata""
}}
],
""body"": ""function(oldDoc, newDoc) {{
return (!oldDoc || JSON.stringify(oldDoc.AttributesByName) !== JSON.stringify(newDoc.AttributesByName))
? newDoc._syncTimestamp
: oldDoc._lastModified
}}""
}} }} }} }}"
),
options: new()
{
IsUpsert = true
},
cancellationToken
);
});
return Task.WhenAll(updateResultTasks);
}
However at least one thing is wrong with this since the value of "_lastModified" is always null
, when I would expect it never should be.但是,这至少有一个问题,因为“_lastModified”的值始终是null
,而我认为它永远不应该是。 If there is no oldDoc, I would expect the value to be set to newDoc._syncTimestamp
which should be the same as personioRecord.SyncTimestamp = DateTime.UtcNow
.如果没有 oldDoc,我希望该值设置为newDoc._syncTimestamp
,它应该与personioRecord.SyncTimestamp = DateTime.UtcNow
相同。
If I switch the order of the AppendStage
s, the value is "ISODate("0001-01-01T00:00:00.000+0000")" instead of null, which is arguably better but still not what is expected or wanted.如果我切换AppendStage
的顺序,则值为“ISODate("0001-01-01T00:00:00.000+0000")”而不是 null,这可以说更好,但仍然不是预期或想要的。
Fwiw, this is the StoredDynamicRecord
class: Fwiw,这是StoredDynamicRecord
class:
public class StoredDynamicRecord : DynamicRecord, IStoredRecord
{
public const string SyncTimestampField = "_syncTimestamp";
public const string LastModifiedTimestampField = "_lastModified";
[BsonId]
public string CacheId { get; set; }
[BsonElement(SyncTimestampField)]
public DateTime SyncTimestamp { get; set; }
[BsonElement(LastModifiedTimestampField)]
public DateTime LastModified { get; set; }
public StoredDynamicRecord From(DynamicRecord dynamicRecord) =>
new()
{
Type = dynamicRecord.Type,
AttributesByName = dynamicRecord.AttributesByName
};
}
What am I missing or doing wrong?我错过了什么或做错了什么?
Couldn't get the above approach to work.无法使上述方法起作用。
This works, but in memory instead of the database:这有效,但在 memory 而不是数据库中:
public Task<StoredDynamicRecord[]> Save(List<StoredDynamicRecord> personioRecords, CancellationToken cancellationToken)
{
IMongoCollection<StoredDynamicRecord> employeeCollection = GetCollection<StoredDynamicRecord>();
List<Task<StoredDynamicRecord>> updateResultTasks = personioRecords.Select(personioRecord =>
{
Dictionary<string, DynamicRecordAttribute> attributesByName = personioRecord.AttributesByName;
string id = (string)attributesByName["id"].Value;
personioRecord.CacheId = string.IsNullOrEmpty(id)
? ObjectId.GenerateNewId()
.ToString()
: id;
DateTime utcNow = DateTime.UtcNow;
personioRecord.SyncTimestamp = utcNow;
StoredDynamicRecord oldRecord = employeeCollection
.Find(x => x.CacheId == personioRecord.CacheId)
.FirstOrDefault();
return employeeCollection.FindOneAndUpdateAsync(
filter: Builders<StoredDynamicRecord>.Filter.Eq(x => x.CacheId, personioRecord.CacheId),
update: Builders<StoredDynamicRecord>.Update
.Set(x => x.CacheId, string.IsNullOrEmpty(id)
? ObjectId.GenerateNewId()
.ToString()
: id
)
.Set(x => x.Type, personioRecord.Type)
.Set(x => x.AttributesByName, attributesByName)
.Set(x => x.SyncTimestamp, personioRecord.SyncTimestamp)
.Set(x => x.LastModified, (!personioRecord.Equals(oldRecord))
? utcNow
: oldRecord.LastModified
),
options: new FindOneAndUpdateOptions<StoredDynamicRecord>()
{
IsUpsert = true
},
cancellationToken
);
})
.ToList();
return Task.WhenAll(updateResultTasks);
}
Note, for this to work, it is important to define equality:请注意,为此,定义相等性很重要:
public override bool Equals(object that) =>
this == that
|| (
that != null
&& that is StoredDynamicRecord otherRecord
&& CacheId == otherRecord.CacheId
&& AttributesByName.Count == otherRecord.AttributesByName.Count
&& AttributesByName.Keys.ForAll(x =>
AttributesByName[x].ToString() == otherRecord.AttributesByName[x].ToString()
)
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.