将函数中的多个函数还原为弹性搜索客户端



我正在使用node和restify构建一个REST API,该API与弹性搜索数据库通信。现在,当我删除一个对象时,我希望它对其他一些对象进行级联删除。我知道这不是真正使用弹性搜索的目的,但请耐心等待。

这是我的代码:

function deleteHostname(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    var endpoints = [];
    client.search({
        index: 'test',
        type: 'something',
        body: {
            from: 0, size: 100,
            query: {
                match: {
                    hostname: 'www.test.com'
                }
            }
        }
    }).then(function (error, resp) {
        if(error) {
            res.send(error);
        }
        endpoints = resp.hits.hits;
        for (index = 0, len = endpoints.length; index < len; ++index) {
            client.delete({
                index: 'test',
                type: 'something',
                id: endpoints[index]._id
            }, function (error, response) {
                if(error) {
                    res.send(error);
                }
            });
        }
        res.send(endpoints);
        return next();
    });
}

所以基本上,我只想搜索任何主机名为www.test.com的对象(我只是硬编码来测试它)。然后我想删除我找到的所有对象。它遵循错误路径并向我发送以下信息:

{  
   "took":1,
   "timed_out":false,
   "_shards":{  
      "total":5,
      "successful":5,
      "failed":0
   },
   "hits":{  
      "total":1,
      "max_score":2.098612,
      "hits":[  
         {  
            "_index":"test",
            "_type":"something",
            "_id":"123456",
            "_score":2.098612,
            "_source":{  
               "duration":107182,
               "date":"2016-05-04 00:54:43",
               "isExceptional":true,
               "hostname":"www.test.com",
               "eta":613,
               "hasWarnings":false,
               "grade":"A+",
               "ipAddress":"ipip",
               "progress":100,
               "delegation":2,
               "statusMessage":"Ready"
            }
         }
      ]
   }
}

所以在我看来,这看起来不像是一个错误?那么,为什么我会把它当作一个错误回来呢?如果我删除:

        if(error) {
            res.send(error);
        }

根据我的代码,我不会得到任何响应。

您需要像这样更改代码(请参阅左侧->表示的更改):

    if(error) {
1->     return res.send(error);
    }
    endpoints = resp.hits.hits;
    for (index = 0, len = endpoints.length; index < len; ++index) {
2->     (function(id){
            client.delete({
                index: 'test',
                type: 'something',
3->             id: id
            }, function (error, response) {
                if(error) {
4->                 next(error);
                }
            });
5->     })(endpoints[index._id]);
    }
6-> //res.send(endpoints);

我现在解释每一个变化:

  1. 如果您不return,您将发送错误,然后继续处理命中
  2. (3/5)由于client.delete是一个异步函数,您需要在匿名函数中调用它
  3. 如果出现错误,您需要调用next(error)而不是res.send
  4. 此时无法发送响应,因为for循环可能尚未终止。您应该使用优秀的async库,而不是for循环(请参阅下面使用asynch.each的示例)

异步示例:

    var async = require('async');
    ...
    if(error) {
        return res.send(error);
    }
    endpoints = resp.hits.hits;
    async.each(endpoints, 
        function(endpoint, callback) {
            client.delete({
               index: 'test',
               type: 'something',
               id: endpoint._id
            }, callback);
        }, 
        // this is called when all deletes are done
        function(err){
            if (err) {
                next(err);
            } else {
                res.send(endpoints);
                next();
            }
        }
    );

另一个解决方案是使用"按查询删除"插件来实现您想要的目的。该功能允许您在一个查询中完成以上所有操作。

如果您仍然使用ES1.x,那么通过查询删除仍然是核心的一部分,您可以简单地调用Javascript客户端的deleteByQuery函数。

如果你在ES2.x上,那么通过查询删除现在是一个插件,所以你需要安装它,然后还需要Javascript客户端的deleteByQuery扩展库

function deleteHostname(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    client.deleteByQuery({
        index: 'test',
        type: 'something',
        body: {
           query: {
               match: { hostname: 'www.test.com' }
           }
        }
    }, function (error, response) {
        if (error) {
            next(error);
        } else {
            res.send(endpoints);
            next();
        }
    });
}

最新更新