32

I am trying to update an existing indexed document. I have indexed tags, title and owners field. Now when the user changes the title, I need to find and update the document inside the index.

Should I update and replace the entire document or just the title field?

public void UpdateDoc(ElasticsearchDocument doc)
{
 Uri localhost = new Uri("http://localhost:9200");
 var setting = new ConnectionSettings(localhost);
 setting.SetDefaultIndex("movies");
 var client = new ElasticClient(setting);

 IUpdateResponse resp = client.Update<ElasticsearchDocument, IndexedDocument>(
                                  d => d.Index("movies")
                                        .Type(doc.Type)
                                        .Id(doc.Id), doc);
}

It just doesn't work. The code above generates a syntax error. Does anyone know the correct way to do this using the C# NEST client of ElasticSearch?

gerosalesc
  • 2,983
  • 3
  • 27
  • 46
kheya
  • 7,546
  • 20
  • 77
  • 109

5 Answers5

25

I have successfully updated existing items in my Elasticsearch index with NEST using a method like the following. Note in this example, you only need to send a partial document with the fields that you wish to be updated.

    // Create partial document with a dynamic
    dynamic updateDoc = new System.Dynamic.ExpandoObject();
    updateDoc.Title = "My new title";

    var response = client.Update<ElasticsearchDocument, object>(u => u
        .Index("movies")
        .Id(doc.Id)
        .Document(updateDoc)
     );

You can find more examples of ways to send updates in the NEST Update Unit Tests from the GitHub Source.

Paige Cook
  • 22,415
  • 3
  • 57
  • 68
20

A better solution in Nest 7.x:

await _client.UpdateAsync<ElasticSearchDoc>(doc.Id, u => u
  .Index("movies")
  .Doc(new ElasticSearchDoc { Title = "Updated title!" }));
mo.
  • 4,165
  • 3
  • 34
  • 45
Ali Bayat
  • 3,561
  • 2
  • 42
  • 43
13

Actually for Nest 2 it's:

dynamic updateFields = new ExpandoObject();
updateFields.IsActive = false;
updateFields.DateUpdated = DateTime.UtcNow;

await _client.UpdateAsync<ElasticSearchDoc, dynamic>(new DocumentPath<ElasticSearchDoc>(id), u => u.Index(indexName).Doc(updateFields))
Jonathon Cwik
  • 987
  • 11
  • 18
4

For Nest 2 to update an POCO that already include an ID field:

 var task = client.UpdateAsync<ElasticsearchDocument>(
                    new DocumentPath<ElasticsearchDocument>(doc), u => 
                        u.Index(indexName).Doc(doc));
gerosalesc
  • 2,983
  • 3
  • 27
  • 46
2

also using Nest 7.x.

If you want to do only a partial update, you can use this method that worked great for me. You must specify "T, K" where T is the full object and K the partial object. Creating a POCO for every partial update is kind of overwork and annoying. For this issue, you can use anonymous object like so

 public bool PartialUpdate(string id, object entity)
 {
     var result = _elasticClient.Update<T, object>(DocumentPath<T>.Id(id), i => i.Index(_indexName).Doc(entity));

     return result.IsValid;
 }

Im using the Elastic Common Schema, so here is an example of a partial object for the update:

new
{
    Labels = new Dictionary<string, object>
    {
        { "EscalateTo", alert.AlertState == AlertState.Escalation ? escalationId : "" },
        { "EscalateFrom", alert.AlertState == AlertState.Descalation ? escalationId : "" },
    },
    Event = new
    {
        End = alert.WindowEnd,
        Duration = (alert.WindowEnd - storedAlert.StartTime.Value).Ticks
    }
};
MaxThom
  • 1,165
  • 1
  • 13
  • 20