Search code examples
c#elasticsearch.net-corenest

ElasticSearch NEST 7.x append item to existing document object array property


I'm looking for a way to append item to existing object list in index document.

I have object defined like this.

public class ElasticIndividual 
    {
        public string? Id{get; set;}        
        public IReadOnlyList<Participation>? ParticipationList{get; set;}
    }

I would like to update ParticipationList with new item. I know that i can override this list with list with added item but i don't have whole list and i don't want to perform search to get this list.

Is it possible to append item instead override?


Solution

  • Script update will help you with this.

    var updateResponse = await elasticClient.UpdateAsync<EsDocument>(
        "1",
        u => u.Script(s => s
            .Source("ctx._source.participations.add(params.item)")
            .Params(objects => objects.Add("item", new Participation {Name = "new item"}))));
    

    Below example app

    class Program
    {
        static async Task Main(string[] args)
        {
            string indexName = "my_index";
            var connectionSettings = new ConnectionSettings(new Uri("http://localhost:9200"));
            connectionSettings.DefaultIndex(indexName);
            var elasticClient = new ElasticClient(connectionSettings);
    
            await elasticClient.Indices.DeleteAsync(indexName);
            var indexResponse = await elasticClient.Indices.CreateAsync(indexName);
    
            var indexDocumentAsync = await elasticClient
                .IndexDocumentAsync(new EsDocument {Id = "1", Participations = new List<Participation> { new Participation { Name = "test" }}});
    
            var updateResponse = await elasticClient.UpdateAsync<EsDocument>(
                "1",
                u => u.Script(s => s
                    .Source("ctx._source.participations.add(params.item)")
                    .Params(objects => objects.Add("item", new Participation {Name = "new item"}))));
        }
    
        class EsDocument
        {
            public string Id { get; set; }
            public List<Participation> Participations { get; set; } = new List<Participation>();
        }
    
        class Participation
        {
            public string Name { get; set; }
        }
    }
    

    Update

    Bulk operation for multiple docs can be constructed like below

    var bulkResponse = await elasticClient.BulkAsync(b => b
        .Update<EsDocument>(u => u
            .Id("1")
            .Script(_ => new InlineScriptDescriptor("ctx._source.participations.add(params.item)")
                .Params(objects => objects.Add("item", new Participation {Name = "new item"}))))
        .Update<EsDocument>(u => u
            .Id("2")
            .Script(_ => new InlineScriptDescriptor("ctx._source.participations.add(params.item)")
                .Params(objects => objects.Add("item", new Participation {Name = "new item"}))))
    );