0

I have a candidate Index where documents are structured like so :

{
  "_index" : "candidates",
  "_type" : "_doc",
  "_id" : "a23OcncBXBMGOH6pwXge",
  "_version" : 1,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "id" : "413",
    "firstname" : "Tania",
    "lastname" : "Stroman",
    "email" : "[email protected]",
    "zip" : "60306",
    "city" : "frankfurt",
    "birthday" : "1978-11-22",
    "tags" : [
      "php",
      "munich"
    ],
    "location" : {
      "lat" : 50.11601257324219,
      "lon" : 8.669955253601074
    }
  }
}

Once a candidate uploads their file, If it's the first uploaded file, I add a field called 'file' to the elastic document. If there are uploaded files in the document already, I push the subsequent uploads to the existing array with the following code :

public function attachCandidateFile($file)
    {
        $client = ClientBuilder::create()->build();

        $params = [
            'index' => 'candidates',
            'id'    => $file['candidate_id']
        ];

        $candidate = $client->get($params);

        if (!is_array($candidate['_source']['file'])) {
            $candidate['_source']['file'] = [];
        } 
        array_push($candidate['_source']['file'], $file);

        $params = [
            'index' => 'candidates',
            'type'  => '_doc',
            'id'    =>  $file['candidate_id'],   
            'body'  => [
                'doc' => [
                    'file' => $candidate['_source']['file']
                ]
            ]                
           
        ];
        $response = $client->update($params);
        echo '<pre>', print_r($response, true) ,'</pre>';
    } 

Is there a way to update the candidate's files directly with the new object without needing the fetch $candidate['_source']['file'] so as to avoid overriding it ?

1 Answer 1

0

Sure -- use an update script when you know which doc to update (using its _id):

POST candidates/_update/a23OcncBXBMGOH6pwXge
{
 "script": {
    "source": """
      if (ctx._source.containsKey('file')) {
        ctx._source.file.add(['filename':params.filename]); // adding a hash map -- could be any JSON primitive
      } else {
        ctx._source.file = [['filename':params.filename]]; // 1-member array
      }
    """,
    "params": {
      "filename": "abc"
    }
  } 
}

Alternatively, use the same script as above but under an _update_by_query call. You can target that document (possible even multiple docs) without ever fetching them.

Sign up to request clarification or add additional context in comments.

6 Comments

It worked well on kibana console. I'm having trouble converting it to php. Any idea on how to do it ?
Unfortunately no, I already managed to make a basic script work. My issue is converting that if else statement. This is my attempt : 'source' => ("ctx._source.containsKey('file')" ? "ctx._source.file.add(params.data)" : "ctx._source.file = [params.data]")
The whole script should be inlined and included in quotes: 'source' => "ctx._source.containsKey('file') ? ctx._source.file.add(params.data) : ctx._source.file = [params.data]" Does this throw an error?
Yes it still does. I found a working alternative though. I initialize the field "file" as an empty array. This way I only need to add to the existing array everytime : 'inline' => "ctx._source.file.add(params.data)". Thank you for your help !
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.