为了账号安全,请及时绑定邮箱和手机立即绑定

将文档属性设置为 null 并在更新时从数据库中删除字段

将文档属性设置为 null 并在更新时从数据库中删除字段

C#
杨__羊羊 2023-07-22 18:40:07
我有下面的 C# 类。public class ElasticSearchDocument{    public string Id { get; set; } = Guid.NewGuid().ToString();    public string Description { get; set; }}我还在我的文档中使用模板,下面的模板用于演示测试。{  "version": 2,  "index_patterns": "documents-test*",  "order": 2,  "aliases": {    "docs-test": {}  },  "settings": {    "number_of_shards": 1  },  "mappings": {    "_doc": {      "dynamic": "strict",      "properties": {        "id": {          "type": "keyword"        },        "description": {          "enabled": false        }      }    }  }}我将该Description属性设置为 ahas value并为其建立索引。下面是数据库中的示例。{  "_index": "documents-test-2019-07-2-2",  "_type": "_doc",  "_id": "55096ff7-5072-4ded-b6a3-94b8e155c9d0",  "_score": 1,  "_source": {    "id": "55096ff7-5072-4ded-b6a3-94b8e155c9d0",    "description": "has value"  }}查询文档,将Description属性设置为null并使用以下 NESTIElasticClient.UpdateAsync方法更新文档。public async Task<Result> UpdateAsync( T document, string indexName = null, string typeName = null, Refresh ? refresh = null, CancellationToken cancellationToken = default) { var response = await Client.UpdateAsync<T,  object>(   document.Id,   u => u.Doc(document)   .Index(indexName ? ? DocumentMappings.IndexStrategy)   .Type(typeName ? ? DocumentMappings.TypeName)   .Refresh(refresh),   cancellationToken); var errorMessage = response.LogResponseIfError(_logger); return errorMessage.IsNullOrEmpty() ? Result.Ok() : Result.Fail(errorMessage);}问题是更新命令后,文档未更改,字段的description值为has value。我认为最合适的解决方案是将 C# 类Description属性设置为 null 并更新 Elastic Search 字段以从文档中删除。
查看完整描述

1 回答

?
HUH函数

TA贡献1836条经验 获得超4个赞

我最终创建了以下方法。


public async Task<Result> UpdateAsync(

    T document, 

    string indexName = null, 

    string typeName = null,

    Refresh? refresh = null, 

    CancellationToken cancellationToken = default)

{

    Guard.Argument(document, nameof(document)).NotNull();


    await RemoveNullFieldsFromDocumentAsync(document, document.Id, indexName, typeName, cancellationToken);


    var response = await Client.UpdateAsync<T, object>(

        document.Id, 

        u => u.Doc(document)

            .Index(indexName ?? DocumentMappings.IndexStrategy)

            .Type(typeName ?? DocumentMappings.TypeName)

            .Refresh(refresh), 

        cancellationToken);


    var errorMessage = response.LogResponseIfError(_logger);


    return errorMessage.IsNullOrEmpty() ? Result.Ok() : Result.Fail(errorMessage);

}


public async Task<Result> UpdateAsync(

    string id, 

    object partialDocument, 

    string indexName = null, 

    string typeName = null,

    Refresh? refresh = null, 

    CancellationToken cancellationToken = default)

{

    Guard.Argument(partialDocument, nameof(partialDocument)).NotNull();

    Guard.Argument(id, nameof(id)).NotNull().NotEmpty().NotWhiteSpace();


    await RemoveNullFieldsFromDocumentAsync(partialDocument, id, indexName, typeName, cancellationToken);


    var response = await Client.UpdateAsync<T, object>(

        id, 

        u => u.Doc(partialDocument)

            .Index(indexName ?? DocumentMappings.IndexStrategy)

            .Type(typeName ?? DocumentMappings.TypeName)

            .Refresh(refresh), 

        cancellationToken);


    var errorMessage = response.LogResponseIfError(_logger);


    return errorMessage.IsNullOrEmpty() ? Result.Ok() : Result.Fail(errorMessage);

}


private async Task<Result> RemoveNullFieldsFromDocumentAsync(

    object document,

    string documentId,

    string indexName = null, 

    string typeName = null,

    CancellationToken cancellationToken = default)

{

    var result = Result.Ok();

    var allNullProperties = GetNullPropertyValueNames(document);

    if (allNullProperties.AnyAndNotNull())

    {

        var script = allNullProperties.Select(p => $"ctx._source.remove('{p}')").Aggregate((p1, p2) => $"{p1}; {p2};");

        result = await UpdateByQueryIdAsync(

                                        documentId, 

                                        script,

                                        indexName,

                                        typeName,

                                        cancellationToken: cancellationToken);

    }


    return result;

}


private static IReadOnlyList<string> GetNullPropertyValueNames(object document)

{

    var allPublicProperties =  document.GetType().GetProperties().ToList();


    var allObjects = allPublicProperties.Where(pi => pi.PropertyType.IsClass).ToList();


    var allNames = new List<string>();


    foreach (var propertyInfo in allObjects)

    {

        if (propertyInfo.PropertyType == typeof(string))

        {

            var isNullOrEmpty = ((string) propertyInfo.GetValue(document)).IsNullOrEmpty();

            if (isNullOrEmpty)

            {

                allNames.Add(propertyInfo.Name.ToCamelCase());

            }

        }

        else if (propertyInfo.PropertyType.IsClass)

        {

            if (propertyInfo.GetValue(document).IsNotNull())

            {

                var namesWithobjectName = GetNullPropertyValueNames(propertyInfo.GetValue(document))

                    .Select(p => $"{propertyInfo.PropertyType.Name.ToCamelCase()}.{p.ToCamelCase()}");

                allNames.AddRange(namesWithobjectName);

            }

        }

    }


    return allNames;

}


public async Task<Result> UpdateByQueryIdAsync(

    string documentId,

    string script,

    string indexName = null, 

    string typeName = null, 

    bool waitForCompletion= false,

    CancellationToken cancellationToken = default)

{

    Guard.Argument(documentId, nameof(documentId)).NotNull().NotEmpty().NotWhiteSpace();

    Guard.Argument(script, nameof(script)).NotNull().NotEmpty().NotWhiteSpace();


    var response = await Client.UpdateByQueryAsync<T>(

        u => u.Query(q => q.Ids(i => i.Values(documentId)))

                .Conflicts(Conflicts.Proceed)

                .Script(s => s.Source(script))

                .Refresh()

                .WaitForCompletion(waitForCompletion)

                .Index(indexName ?? DocumentMappings.IndexStrategy)

                .Type(typeName ?? DocumentMappings.TypeName), 

        cancellationToken);


    var errorMessage = response.LogResponseIfError(_logger);


    return errorMessage.IsNullOrEmpty() ? Result.Ok() : Result.Fail(errorMessage);

}



查看完整回答
反对 回复 2023-07-22
  • 1 回答
  • 0 关注
  • 84 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信