How do I query a null date inside an array in elasticsearch?

Viewed 58

In an elasticsearch query I am trying to search Document objects that have an array of approval notifications. The notifications are considered complete when dateCompleted is populated with a date, and considered pending when either dateCompleted doesn't exist or exists with null. If the document does not contain an array of approval notifications then it is out of the scope of the search.

I am aware of putting null_value for field dateCompleted and setting it to some arbitrary old date but that seems hackish to me.

I've tried to use Bool queries with must exist doc.approvalNotifications and must not exist doc.approvalNotifications.dateCompleted but that does not work if a document contains a mix of complete and pending approvalNotifications. e.g. it only returns document with ID 2 below. I am expecting documents with IDs 1 and 2 to be found.

How can I find pending approval notifications using elasticsearch?

PUT my_index/_mapping/Document

 "properties" : {
  "doc" : {
    "properties" : {
      "approvalNotifications" : {
        "properties" : {
          "approvalBatchId" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "approvalTransitionState" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "approvedByUser" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "dateCompleted" : {
            "type" : "date"
          }
        }
      }
    }
  }
}

Documents:

{
    "id": 1,
    "status": "Pending Notifications",
    "approvalNotifications": [
        {
            "approvalBatchId": "e6c39194-5475-4168-9729-8ddcf46cf9ab",
            "dateCompleted": "2018-11-15T16:09:15.346+0000"
        },
        {
            "approvalBatchId": "05eaeb5d-d802-4a28-b699-5e593a59d445",
        }
    ]
}

{
    "id": 2,
    "status": "Pending Notifications",
    "approvalNotifications": [
        {
            "approvalBatchId": "e6c39194-5475-4168-9729-8ddcf46cf9ab",
        }
    ]
}

{
    "id": 3,
    "status": "Complete",
    "approvalNotifications": [
        {
            "approvalBatchId": "e6c39194-5475-4168-9729-8ddcf46cf9ab",
            "dateCompleted": "2018-11-15T16:09:15.346+0000"
        },
        {
            "approvalBatchId": "05eaeb5d-d802-4a28-b699-5e593a59d445",
            "dateCompleted": "2018-11-16T16:09:15.346+0000"            
        }
    ]
}

{
    "id": 4
    "status": "No Notifications"
}
1 Answers

You are almost there, you can achieve the desired behavior by using nested datatype for the "approvalNotifications" field.

What happens is that Elasticsearch flattens your approvalNotifications objects, treating their subfields as subfields of the original document. The nested field instead will tell ES to index each inner object as an implicit separate object, though related to the original one.

To query nested objects one should use nested query.

Hope that helps!

Related