Reputation: 1125
I have a list inside my ElasticSearch index. How can i add a new element to the list using NEST 2? I have already searched an answer to my problem, but all that i found are answer for the version 1.x, and it doesn't work for me.
MODEL:
public class TicketModel
{
public Guid Id { get; set; }
public Guid IdUser { get; set; }
public Guid IdAuthor { get; set; }
public Guid? IdAssignedUser { get; set; }
public Guid? IdAsset { get; set; }
public Guid? IdOwner { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? ClosingDate { get; set; }
public DateTime? DueDate { get; set; }
public DateTime? LastDateUserView { get; set; }
public DateTime? LastDateAssignedUserView { get; set; }
public string TicketCode { get; set; }
public string Title { get; set; }
public int IdCategory { get; set; }
public int? IdSubcategory { get; set; }
public short? IdPriority { get; set; }
public short IdState { get; set; }
public bool IsNew { get; set; }
public List<TicketMessageModel> TicketMessageList { get; set; }
}
public class TicketMessageModel
{
public Guid Id { get; set; }
public Guid IdTicket { get; set; }
public Guid IdUserFrom { get; set; }
public Guid? IdUserTo { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? DeleteDate { get; set; }
public string Message { get; set; }
public bool HideToFinalUser { get; set; }
public byte? MessageType { get; set; }
public List<TicketMessageFilesModel> MessageFileList { get; set; }
}
public class TicketMessageFilesModel
{
public Guid Id { get; set; }
public Guid? IdTicketMessage { get; set; }
public string FileName { get; set; }
public string FileTitle { get; set; }
public string FileOriginalName { get; set; }
public byte FileType { get; set; }
}
I have tried to find a way out using the other answers, but i got stuck here:
client.Update<ElasticSearchTickets.TicketMessageModel, object>(new DocumentPath<ElasticSearchTickets.TicketMessageModel>(elem.Id),
q => q.Script(x => x.Inline("ctx._source.MessageFileList += elem"))./*??*/);
thanks in advance.
EDIT:
Here is the code i tried to insert a new element inside of my list:
ElasticSearchTickets.TicketMessageModel elem = new ElasticSearchTickets.TicketMessageModel()
{
CreationDate = message.CreationDate,
DeleteDate = message.DeleteDate,
HideToFinalUser = message.HideToFinalUser,
Id = message.Id,
IdTicket = message.IdTicket,
IdUserFrom = message.IdUserFrom,
IdUserTo = message.IdUserTo,
Message = message.Message,
MessageType = message.MessageType,
MessageFileList = tempList
};
var response = client.Update<ElasticSearchTickets.TicketModel, object>(new DocumentPath<ElasticSearchTickets.TicketModel>(elem.IdTicket.ToString()), q => q
.Script(s => s
.Inline("if (ctx._source.TicketMessageList == null) { ctx._source.TicketMessageList = element; } else { ctx._source.TicketMessageList += element; }")
.Params(d => d.Add("element", new [] { elem }))
));
But now i got a Server Error, because the property "element" has not be declared. How to fix this?
Here is the mapping:
"mappings": {
"ticket": {
"properties": {
"ClosingDate": {
"type": "date"
},
"CreationDate": {
"type": "date"
},
"DueDate": {
"type": "date"
},
"Id": {
"type": "keyword"
},
"IdAsset": {
"type": "keyword"
},
"IdAssignedUser": {
"type": "keyword"
},
"IdAuthor": {
"type": "keyword"
},
"IdCategory": {
"type": "integer"
},
"IdOwner": {
"type": "keyword"
},
"IdPriority": {
"type": "short"
},
"IdState": {
"type": "short"
},
"IdSubcategory": {
"type": "integer"
},
"IdUser": {
"type": "keyword"
},
"IsNew": {
"type": "boolean"
},
"LastDateAssignedUserView": {
"type": "date"
},
"LastDateUserView": {
"type": "date"
},
"TicketCode": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"TicketMessageList": {
"type": "nested",
"properties": {
"CreationDate": {
"type": "date"
},
"DeleteDate": {
"type": "date"
},
"HideToFinalUser": {
"type": "boolean"
},
"Id": {
"type": "keyword"
},
"IdTicket": {
"type": "keyword"
},
"IdUserFrom": {
"type": "keyword"
},
"IdUserTo": {
"type": "keyword"
},
"Message": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"MessageFileList": {
"properties": {
"FileName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileOriginalName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileTitle": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileType": {
"type": "short"
},
"Id": {
"type": "keyword"
},
"IdTicketMessage": {
"type": "keyword"
}
}
},
"MessageType": {
"type": "short"
}
}
},
"Title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
Upvotes: 2
Views: 2955
Reputation: 125498
Here's a stripped down example
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "default-index";
var connectionSettings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex);
var client = new ElasticClient(connectionSettings);
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
client.CreateIndex(defaultIndex, c => c
.Mappings(ms => ms
.Map<TicketMessageModel>(m => m
.AutoMap()
.Properties(p => p
.Nested<TicketMessageFilesModel>(n => n
.Name(nn => nn.MessageFileList)
.AutoMap()
)
)
)
)
);
var id = "ticketmessage";
client.Index(new TicketMessageModel
{
Id = id,
MessageFileList = new List<UserQuery.TicketMessageFilesModel>
{
new TicketMessageFilesModel { Id = "file1" }
}
});
client.Update<TicketMessageModel, object>(id, q => q
.Script("if (ctx._source.messageFileList == null) { ctx._source.messageFileList = elem; } else { ctx._source.messageFileList += elem; }")
.Params(d => d
.Add("elem", new[] { new TicketMessageFilesModel { Id = "file2" } })
)
);
var getResponse = client.Get<TicketMessageModel>(id);
}
public class TicketMessageModel
{
public string Id { get; set; }
public List<TicketMessageFilesModel> MessageFileList { get; set; }
}
public class TicketMessageFilesModel
{
public string Id { get; set; }
}
getResponse
JSON response is
{
"_index" : "default-index",
"_type" : "ticketmessagemodel",
"_id" : "ticketmessage",
"_version" : 2,
"found" : true,
"_source" : {
"id" : "ticketmessage",
"messageFileList" : [ {
"id" : "file1"
}, {
"id" : "file2"
} ]
}
}
Some points of interest:
_source
. By default, NEST camel cases POCO property names when serializing to field names in ElasticsearchEDIT:
It looks like you are working with NEST 5.x against Elasticsearch 5.x; the default scripting language in 5.x is Painless as opposed to Groovy in 2.x and so there are some small subtle differences to the script that must be made.
Here's a version that works on 5.x with Painless
client.Update<TicketMessageModel, object>(id, q => q
.Script(s => s
.Inline("if (ctx._source.messageFileList == null) { ctx._source.messageFileList = new ArrayList(); } ctx._source.messageFileList.add(params.elem);")
.Params(d => d
.Add("elem", new TicketMessageFilesModel { Id = "file2" })
)
)
);
Check out the guide on Painless for more details. You can also use the original example with Groovy too, by specifying .Lang("groovy")
inside of .Script()
but you would also need to allow inline Groovy scripts to run by adding
script.engine.groovy.inline: true
to the Elasticsearch.yml configuration. Groovy scripts are disabled by default for security reasons.
Upvotes: 3