繁体   English   中英

在 C# 中,使用 Mongo 驱动程序,如何设置“最后修改字段”?

[英]In C#, using the Mongo Driver, how can I set a "last modified field"?

因为 Personio 的 API 不会告诉我何时创建或修改了员工,这给我们带来了可扩展性问题,所以我正在创建一个缓存,我可以在其中存储 Personio 的元数据,包括是否/何时修改。

我已经从@Charchit Kapoor 了解到,我应该能够使用 $addFields 和 $function 来填充“lastModified”值,所以现在我正试图在我的 C# 应用程序中完成这项工作。

我创建了以下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);
    }

但是,这至少有一个问题,因为“_lastModified”的值始终是null ,而我认为它永远不应该是。 如果没有 oldDoc,我希望该值设置为newDoc._syncTimestamp ,它应该与personioRecord.SyncTimestamp = DateTime.UtcNow相同。

如果我切换AppendStage的顺序,则值为“ISODate("0001-01-01T00:00:00.000+0000")”而不是 null,这可以说更好,但仍然不是预期或想要的。

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

我错过了什么或做错了什么?

无法使上述方法起作用。

这有效,但在 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);
    }

请注意,为此,定义相等性很重要:

    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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM