0

I have this document and I want to sort this way :

  • if the value 1 is in the field id_status_viewed, then the document's weight for sorting is 1
  • if the value 1 is in the field id_status_new, then the document's weight for sorting is 0

I want to sort based on the weight, in a top hits aggregation. Example :

{
    "string_ticket_name": "ticket D",
    "object_tasks": [
        {
            "user_id": 1,
            "id_status_viewed": [
                1
            ],
            "id_status_new": [0]
        }
    ]
}

This is what I tried :

{
    "aggs": {
        "object_tasks": {
            "nested": {
                "path": "object_tasks"
            },
            "aggs": {
                "names": {
                    "top_hits": {
                        "sort": [
                            {
                                "_script": {
                                    "type": "number",
                                    "script": {
                                        "lang": "painless",
                                        "source": "for (item in params._source.id_status_viewed) { if (item == 1) {return 2;}} for (item in params._source.id_status_new) { if (item == 1) {return 0;}}"
                                    },
                                    "order": "asc"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
}

but for some reason I can't access id_status_viewed

"script_stack": [
                    "for (item in params._source.id_status_viewed) { ",
                    "                           ^---- HERE"
                ],
"reason": "Cannot invoke \"Object.getClass()\" because \"receiver\" is null"

more details below (mapping)

{
    "mappings": {
        "properties": {
            "object_views": {
                "type": "nested",
                "properties": {
                    "number_rank": {
                        "type": "double"
                    },
                    "string_status": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword"
                            }
                        }
                    },
                    "user_id": {
                        "type": "long"
                    }
                }
            },
            "string_ticket_name": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                }
            },
            "object_tasks": {
                "type": "nested",
                "properties": {
                    "string_ticket_name": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword"
                            }
                        }
                    },
                    "user_id": {
                        "type": "long"
                    }
                }
            }
        }
    }
}
misterone
  • 191
  • 2
  • 9

1 Answers1

1

When inside a nested context, you cannot iterate over the nested parent -- you can only access the "current" nested subdocument. That said, instead of params._source you'd use the doc[...] notation:

{
  "aggs": {
    "object_tasks": {
      "nested": {
        "path": "object_tasks"
      },
      "aggs": {
        "names": {
          "top_hits": {
            "sort": [
              {
                "_script": {
                  "type": "number",
                  "script": {
                    "lang": "painless",
                    "source": """
                      def status_viewed = doc['object_tasks.id_status_viewed'].empty ? null : doc['object_tasks.id_status_viewed'].value;
                      def status_new = doc['object_tasks.id_status_new'].empty ? null : doc['object_tasks.id_status_new'].value;
                      
                      if (status_viewed == 1) { return 2; }
                      if (status_new == 1) { return 0; }
                      
                      // fallback
                      return Long.MAX_VALUE;
                    """
                  },
                  "order": "asc"
                }
              }
            ]
          }
        }
      }
    }
  }
}
Joe - GMapsBook.com
  • 15,787
  • 4
  • 23
  • 68
  • Thanks, this worked. So doc['object_tasks.id_status_viewed'] is the correct way to access the document and params._source.id_status_viewed means that I would be trying to access another context than the nested object itself, so it can't work. For people having trouble with the """ """ in Joe's solution, using simple quotes (" ") works just fine. – misterone Apr 29 '21 at 18:25
  • 1
    True true. Yes, single quotes are the way to go in order to work with valid json. BTW Kibana can help you convert multiline JSON into regular, valid JSON, just as I described in the last point of https://stackoverflow.com/a/61960046/8160318 – Joe - GMapsBook.com Apr 29 '21 at 20:18