Elasticsearch NodeJS : Cannot return properly

1.2k Views Asked by At

I am trying to return the results from an elasticsearch query. This is my webpage

<!DOCTYPE html>
 <html>

  <head>
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
  </head>

 <script>
 $(document).ready(function() {
 $('#ping-button').click(function(e) {
    e.preventDefault();

    var val;
    $.ajax({
        type: 'POST',
        url: 'http://localhost:6002/esPingTest',
        success: function(data){
        alert(data);
        alert("Yay");
        val=data;
        document.getElementById("demo").innerHTML = val;
        },
        error: function(){
        alert("Nay");
        }
    });


});
});
 </script>
<body>


<center>
<button id='ping-button'>Ping</button>
<br><br>
<p id="demo"></p>
</center>
</body>
</html>

so i have a button, and when i click on it, its supposed to go to the esPingTest method.

Here is my app.js

var express = require('express');
var app = express();
var cfenv = require('cfenv');
var bodyParser = require('body-parser');
var port = (process.env.VCAP_APP_PORT || 3000);
var host = (process.env.VCAP_APP_HOST || 'localhost');

// Create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })

app.use(express.static('elastic'));

var appEnv = cfenv.getAppEnv();

//start server on the specified port and binding host
var server = app.listen(appEnv.port, '0.0.0.0', function() {

      console.log("server starting on " + appEnv.url);
    })

app.get('/index.html', function (req, res) {
   res.sendFile( __dirname + "/" + "index.html" );
})


app.post('/esPingTest', urlencodedParser, function (req, res) {

   console.log("Ping");
   docs = getEsDocs()
   console.log(docs)
   res.end(JSON.stringify(docs));
})

function getEsDocs()
{
    var elasticsearch = require('elasticsearch');
    var client = elasticsearch.Client({
      host: 'localhost:9200',
      log: 'trace'
    });

    client.ping({
      // ping usually has a 3000ms timeout
      requestTimeout: Infinity,

      // undocumented params are appended to the query string
      hello: "elasticsearch!"
    }, function (error) {
      if (error) {
        console.trace('Elasticsearch cluster is down!');
        return "Error:Elasticsearch cluster is down!"
      } else {
        console.log('All is well');
        ff = getmeres(client);
        console.log("ping")
        console.log(ff)
        return ff
        //alert("YAY");
      }
    });

    function getmeres(client)
    {

        var xox =
        client.search({
              index: 'researchtest',
              body: {

                      "aggs": {
                        "docs": {
                          "terms": {
                            "field": "DocumentID"
                          }
                        }
                      }

              }
            }, function (error, response) {
                if (error) {
                    console.trace('Search query failed');
                    return "Error:Search query failed"
                  } else {
                    console.log('All is well');
                    d=response;
                    console.log("getmeres");
                    x=showdocs(d);
                    console.log("inner xo is"+xo);
                    var xo=x;
                    console.log("inner xo is"+xo);

                  }
            });
        console.log("outer xox is"+xox);
        return xox;
    }


    function showdocs(d){
        da=d.hits.hits
        var docs=[]
        for (i=0;i<da.length;i++)
        {   
            docs.push(da[i]["_source"]["DocumentID"]);
        }
        console.log("showdocs")
        console.log(docs)
        return docs;
    }

}

so i am calling the showdocs() function from inside the else condition of the client.search function

at the end i do not see any value returned as a result of return xo

here is the result i get

getmeres
showdocs
[ '12',
  '12',
  '23' ]
inner xo is[object Object]
inner xo 12,12,23

how do i get the value of xo back after the assignment xo=x?

why did the last console.log("outer xox is"+xox); not get printed at all?

i cant figure out how to return my result back to my webpage

Edit

Thanks @peteb for the answer. now here is my call

var ff =  getmeres(client, function getmeresResult(err, result){
              if (err) return err;
              console.log("Got res "+result);
              return result;          
            });
        console.log("ping")
        console.log(ff)
        return ff;

and the getmeres is as you had advised. Now i get

showdocs [ '12', '12', '23' ] Got res 12,12,23

which is great! but it still does not assign the value back to ff. I need to return ff back to getEsDocs

should i call getEsDocs in the same way as getmeres? with a callback? if so, will the following call work

docs = getEsDocs(function getDocResult(err, result){
      if (err) return err;
      console.log("Got doc "+result);
      return result;          
    })
   console.log(docs)
   res.end(JSON.stringify(docs));

Almost there

thanks again, i think i am nearly there

here is my first call

getEsDocs(function getDocResult(err, result){
      if (err) return err;
      console.log("Got doc "+result);
      res.end(JSON.stringify(result));
      return result;          
    })

here is my second call

function getEsDocs(callback)
{
    var elasticsearch = require('elasticsearch');
    var client = elasticsearch.Client({
      host: 'localhost:9200',
      log: 'trace'
    });

    client.ping({
      // ping usually has a 3000ms timeout
      requestTimeout: Infinity,

      // undocumented params are appended to the query string
      hello: "elasticsearch!"
    }, function (error) {
      if (error) {
        console.trace('Elasticsearch cluster is down!');
        return "Error:Elasticsearch cluster is down!"
      } else {
        console.log('All is well');
        return callback(null, getmeres(client, function getmeresResult(err, result){
              if (err) return err;
              console.log("Got res "+result);
              return result;          
            }));
      }
    });

it still prints

showdocs
    [ '12',
      '12',
      '23' ]
    Got res 12,12,23

what am i missing?

Nearly

so this is what i have, as you suggested

app.post('/esPingTest', urlencodedParser, function (req, res) {

   console.log("Ping");
   getEsDocs(function getEsDocsResult(err, result) {
        if (err) return res.status(400).json(result);
        console.log("Got doc"+result)
        return res.status(200).json(result); 
      });

});

function getEsDocs(callback)
{
    var elasticsearch = require('elasticsearch');
    var client = elasticsearch.Client({
      host: 'localhost:9200',
      log: 'trace'
    });

    client.ping({
      // ping usually has a 3000ms timeout
      requestTimeout: Infinity,

      // undocumented params are appended to the query string
      hello: "elasticsearch!"
    }, function (error) {
      if (error) {
        console.trace('Elasticsearch cluster is down!');
        return "Error:Elasticsearch cluster is down!"
      } else {
        console.log('All is well');
        return callback(null, getmeres(client, getmeresResult));
        function getmeresResult(err, result)
        {
              if (err) return err;
              console.log("Got res "+result);
              return result;          
            }
      }
    });


}

but i still dont see the final return! can you see anything that is wrong?

so basically this return

if (err) return err;
              console.log("Got res "+result);
              return result;  

does not work!

2

There are 2 best solutions below

12
peteb On

Your final console.log("outer xox is"+xox); is not getting fired because it is executing immediately after calling client.search() since that call is async and won't block execution from continuing within that function. xox will be undefined when that happens and since console.log() won't print if what it's trying to print is concatenated with undefined.

Your current implementation of getmeres() is going to always return undefined because you're returning from outside the callback instead of handling the result of client.search() and then returning that value back to the caller from within the callback.

You can get the value out of getmeres() by taking a callback function as a parameter and returning the callback with the result. See the below example with an error first callback being taken as the second parameter of getmeres().

function getmeres(client, callback) {
  client.search({
    index: 'researchtest',
    body: {
      "aggs": {
        "docs": {
          "terms": {
            "field": "DocumentID"
          }
        }
      }
    }
  }, function (error, response) {
    if (error) return callback(error, null); // returns the callback with the error that happened

    return callback(null, showdocs(response));  // returns the result of showdocs(response)
});

Example of calling getmeres() with the callback as a second param

getmeres(client, function getmeresResult(err, result) {
  if (err) return err;

  return result;          
});

var elasticsearch = require('elasticsearch');, require() statements are synchronous and you shouldn't be places this inside getEsDocs because everytime this route is hit, you will block all operations being handle by the main thread running your express server

Get the value back to the route:

app.post('/esPingTest', urlencodedParser, function (req, res) {
  getEsDocs(function getEsDocsResult(err, result) {
    if (error) return res.status(400).json(result);

    return res.status(200).json(result); 
  });
});

function getEsDocs(callback) {
  var client = elasticsearch.Client({
    host: 'localhost:9200',
    log: 'trace'
  });

  client.ping({
    // ping usually has a 3000ms timeout
    requestTimeout: Infinity,
    // undocumented params are appended to the query string
    hello: "elasticsearch!"
  }, function (error) {
      if (err) return callback(error, null);

      return callback(null, getmeres(client, getmeresResult));

      function getmeresResult(err, result) {
        if (err) return err;

        return result;          
      });
});
1
jmcgriz On

The problem is most likely that you're using xo multiple times. The line that's failing is attempting to reassign the value of xo to x while you're still inside of a function call that's supposed to be returning a value to xo. If you get rid of var xo = at the beginning, or change it to a different variable name, you should see it run properly.