Using 'painless' script to add / append to a nested field

Using 5.0.0-alpha4:
I've come across this in the elasticsearch repo, which is helpful, although not all the examples work. The one that tries to append a tag "blue" to the existing field "tags":["red"] fails with an error "Cannot cast java.lang.String to java.util.ArrayList".

I have a document with a nested 'views' field, containing a 'user' and a 'count' value.

"views":
[{"count": 2,
"user": "tt99"},
{"count":1,
"user: "tt88"}]

I'm trying to figure out a 'painless' script that, depending on the supplied parameters, either:
(a) adds the field "views", along with a user and default count of 1, when the field does not pre-exist;
(b) where the field does pre-exist, it appends the new user and a default count of 1 to the views array; or
(c) where both the field and user pre-exist, it just increments the counter by one, but doesn't duplicate the user.

I have tried this (which I know doesn't handle the field not pre-existing):

POST index/type/12345/_update
{
"script": {
"lang": "painless",
"inline": "if (ctx._source.views.user === params.view.user) {ctx._source.views.count += params.view.count} else {ctx._source.views += params.view}",
"params": {
"view": {"user":"tt99", "count":1}
}
}
}

However, it doesn't like how I am reference user: "Illegal list shortcut value [user]."

In the case above, I would expect, as my result, the count to increment to 3. If my params were {"user":"tt77", "count":1}, I would expect a new user "tt77" with count of 1 to get appended to the views array.

Should I be somehow looping through the json docs within the views array? I have seen a groovy example referencing a 'containskey' function .. but I tried that in 'painless' without any joy.

If someone could point me in the right direction, that would be much appreciated.

Thanks,
Colum

I subsequently tried this with groovy, having not been able to find enough documentation on painless:

{
"script" : "for (int i = 0; i < ctx._source.views.size(); i++) {if(ctx._source.views[i].user == view.user){ctx._source.views[i].count++;} else {ctx._source.views.add(view)}}",
"lang": "groovy",
"params": {
"view": {"user":"tt99", "count":1}
}
}

So, having had originally had just user tt88, I ran the above one, which gave me {"user": "tt99", "count": "2"} ... instead of count 1 ... and running it twice, repeats the user ... and increments to count 3! Obviously my attempt at pushing the whole 'view' param if no user is found is failing ... and resulting in incorrect entries ... but I don't have enough experience with groovy to solve this!

"views": [
{
"count": 1,
"user": "tt88"
},
{
"count": 3,
"user": "tt99"
},
{
"count": 2,
"user": "tt99"
}
]

I would still very much appreciate a 'painless' solution to this too ... as a learning mechanism .. and to help others that might stop by here. Thanks.

JSON arrays really don't retain any clue as to if their contents should be treated as a Map (as in your example) or a List or a Set etc.
I've used this before in a Groovy update script:

// Convert basic array into map for ease of manipulation
vendorMap = doc.vendorSummaries.collectEntries{[it.vendorName, it]};

See the full script in http://bit.ly/entcent ReviewerProfileUpdater.groovy

Thanks Mark ... will need to get my head around this one ... and report back!