2015-05-19 79 views
0

我期待做一个get,在结果上运行一个函数,它将通过更新一个字段来进行一些操作,然后将该文档回到数据库中。真的,我的问题是能够链接多个数据库调用。过去一周左右我一直在努力。任何建议表示赞赏,谢谢。从rethinkdb数据库获取数据,处理所述数据,然后用操纵的文档更新数据库

这是我迄今为止尝试过,但是我收到一个错误:

function geocode_cleanup(request, response, next) { 
    r.table('dealer_locations').filter(r.row('geodata').match('No geodata found.')) 
    .do(function(row) { 
     var geodata = opencage_geocoder.geocode(row.Address, function(error, response) { 
     if (error) { 
      console.log("Error."); 
      row.geodata = "No geodata found."; 
      row.active = true; 
     } else if (response.length == 0) { 
      console.log("Empty response."); 
     } else { 
      console.log("Success."); 
      console.log(response); 
      var latitude = response[0].latitude; 
      var longitude = response[0].longitude; 
      row.geodata = r.point(longitude, latitude); 
      row.active = true; 
     } 
     }); 
     return r.table('dealer_locations').update({ 
     geodata: geodata 
     }) 
    }).run(conn, function(error, cursor) { 
     response.setHeader("Content-Type", "application/json"); 
     if (error) { 
     handleError(response, error); 
     } else { 
     cursor.toArray(function(error, results) { 
      if (error) { 
      handleError(response, error); 
      } else { 
      response.send(results); 
      }; 
     }); 
     } 
     next(); 
    }) 
}; 

而且,这给在响应中返回了预期的效果,但第二个分贝行动从未发生过,因为我还在里面我认为相同的db连接:

function geocode_cleanup(request, response, next) { 
    var conn = request._rdbConn; 
    r.table('dealer_locations').filter({geodata: "No geodata found."}).run(conn, function(error, cursor) { 
     if (error) { 
     handleError(response, error); 
     } else { 
     cursor.toArray(function(error, results) { 
      if (error) { 
      handleError(response, error); 
      } else { 
      var i = 1; 
      async.forEach(results, function(item, callback) { 
      var address = (item.Address + " " + item.City).toString(); 
      opencage_geocoder.geocode(address, function(err, res) { 
       if (err) { 
       console.log(i); 
       console.log("Error."); 
       item.id = i; 
       item.geodata = "No geodata found."; 
       item.active = true; 
       i++; 
       callback(); 
       } else if (res.length == 0) { 
        console.log(i); 
        console.log("Empty response."); 
        i++; 
        callback(); 
       } else { 
        console.log(i); 
        console.log("Success."); 
        console.log(res); 
        var latitude = res[0].latitude; 
        console.log(i + " " + latitude); 
        var longitude = res[0].longitude; 
        console.log(i + " " + longitude); 
        item.id = i; 
        item.geodata = r.point(longitude, latitude); 
        item.active = true; 
        i++; 
        callback(); 
       } 
       }); 
      }, function() { 
       r.table('dealer_locations').insert(results, { 
       conflict: "replace" 
       }).run(request._rdbConn, function(error, results) { 
       if (error) { 
        console.log("Data not inserted!"); 
       } else { 
        console.log("Data inserted!"); 
       } 
       }); 
       console.log("Done!"); 
       response.send(results); 
      }); 
      } 
     }) 
     } 
    }) 
    } 
+0

哪一个是从未发生过的第二个分贝行动? –

+0

插入。 。 'r.table( 'dealer_locations')INSERT(结果,{ 冲突: “代替” })运行(request._rdbConn,功能(错误,结果){ 如果(错误){ 的console.log。 (“Data not inserted!”); } else { console.log(“Data inserted!”); } });' –

+0

您在第一个错误中遇到什么错误?请记住,例如,您不能在ReQL的匿名函数中(例如'do')运行JavaScript函数。这些函数是在服务器上发送和执行的(例如,它不能访问'opencage_geocoder') –

回答

1

这里是它使用的承诺,组织代码一点点可能的解决方案。

// Guarantee support for promises and provide the `promisify` function 
var Promise = require('bluebird'); 
// Promisify the geocode function to make it easier to use 
var geocode = Promise.promisify(opencage_geocoder.geocode); 

function geocode_cleanup(request, response, next) { 
    var conn = request._rdbConn; 
    r 
    .table('dealer_locations') 
    .filter(r.row('geodata').match('No geodata found.')) 
    .coerceTo('array') 
    .run(conn) 
    .then(function(rows) { 
     // This promise will be resolve when all rows have been geocoded and updated 
     // We map the rows into an array of promises, which is what Promise.all takes 
     return Promise.all(rows.map(function (row) { 
     return geocode(row.Address) 
      .then(function (response) { 
      console.log("Success."); 
      var latitude = response[0].latitude; 
      var longitude = response[0].longitude; 
      row.geodata = r.point(longitude, latitude); 
      row.active = true; 
      // Return the row 
      return row; 
      }); 
     }); 
     })); 
    }) 
    .then(function (rows) { 
     // Now that all `dealer_locations` have been updated, re-query them 
     return r 
     .table('dealer_locations') 
     .insert(rows, {conflict: "update", return_changes: true}) 
     .run(conn); 
    }) 
    .then(function (results) { 
     // Send the response; 
     response.setHeader("Content-Type", "application/json"); 
     response.send(results); 
     return; 
    }) 
    .catch(function (err) { 
     return handleError(null, error); 
    }) 
}; 

一些问题,我与你的代码注意:

1.使用do

r.table('dealer_locations').filter(r.row('geodata').match('No geodata found.')) 
    .do(function(row) { 
     var geodata = opencage_geocoder.geocode ... 
    }) 

在此代码段,您使用的是JS功能内的do。你不能那样做。请记住,do内发生的事情发生在RethinkDB服务器(不在您的Node.js服务器中)。你的RethinkDB服务器不知道你的opencage_geocoder函数,所以这没有用。

无论do返回都必须是有效的ReQL查询或ReQL表达式。你不能在其中执行任意的JavaScript。

如果你想运行JavaScript与你的查询结果,你必须.run的查询,然后做任何你想做的回调或.then函数内。此时,该代码将在JavaScript中执行,而不是在RethinkDB服务器中执行。

使用

2. update

return r.table('dealer_locations').update({ 
    geodata: geodata 
}) 

update方法只能更新一个文件。您无法传递一组文档。在这种情况下,你需要做什么r.table().get().update()为了这个工作,因为你必须引用一个文件,当你update东西。

如果您有一组要更新的文档,则可以使用forEach方法。

r.table('hello') 
.merge({ 
    'new_property': 'hello!' 
}) 
.forEach(function (row) { 
    // Insert that property into the document 
    return r.table('hello').get(row.id).update(row); 
}) 

你也可以做到这一点(你已经这样做):

r.table('hello') 
.merge({ 
    'new_property': 'hello!' 
}) 
.do(function (rows) { 
    // Insert that property into the document 
    return r.table('hello') 
    .insert(rows, {conflict: "update", return_changes: true}); 
}) 
+0

首先,感谢详细的响应。由于误解了如何使用某些ReQL函数,您清除了我认为我遇到的其他一些问题。但是没问题,我认为除了一件事之外,这将起作用。我正在查找的行“地理数据”是数据库中的地理类型。当我在数据库插入数据的过程中进行初始地理编码时,如果地址解析过程中出现地址错误,我通常只需将我的函数放入行中找不到地理数据。现在当我运行你发布的函数时,在地理数据列中有一个字符串会给我一个错误。 –

+0

我换出了所有“找不到地理数据”。值为null,但我仍然收到此错误: '未处理的拒绝RqlRuntimeError:期望的类型STRING,但在PTY.rr.table(“dealer_locations”)中找到PTYPE 。filter(r.row(“geodata”)。match(null))' –

+0

'match'用于字符串。如果你在任何不是字符串的地方调用'match',它会引发错误。试试'.filter(r.row(“geodata”)。eq(null))''。 –

0

好的,我有一个建议。这会查询您感兴趣的文档,修改它们(在您的应用服务器上,而不是在数据库中),然后使用漂亮的conflict: 'update'选项重新插入它们。它也使用承诺,因为我认为这有点干净。

function geocode_cleanup(request, response, next) { 
    r.table('dealer_locations') 
     .filter(r.row('geodata').match('No geodata found.')) 
     .run(conn).then(function(cursor) { 
      var to_update = []; 
      return cursor.toArray().then(function getGeocodes(rows) { 
       return rows.map(function getGeocode(row) { 
        row.geodata = opencage_geocoder.geocode(row.Address, function(error, response) { 
         if (error) { 
          console.log("Error."); 
          row.geodata = "No geodata found."; 
          row.active = true; 
         } else if (response.length == 0) { 
          console.log("Empty response."); 
         } else { 
          console.log("Success."); 
          console.log(response); 
          var latitude = response[0].latitude; 
          var longitude = response[0].longitude; 
          row.geodata = r.point(longitude, latitude); 
          row.active = true; 
         } 
        }); 
        return row; 
       }); 
      }); 
     }).then(function doneGeocoding(modified_rows){ 
      return r.table('dealer_locations') 
       .insert(modified_rows, {conflict: "update", return_changes: true})('changes') 
       .coerceTo('array') 
       .run(conn); 
     }).then(function finishResponse(changes){ 
      response.setHeader("Content-Type", "application/json"); 
      response.send(results); 
      next(); 
     }).catch(function(err) { 
      // handle errors here 
     }); 
}; 

买者自负,我没有跑这一点,所以有可能是语法错误和事物

+0

对不起,这样的延迟响应。我运行了你的代码,虽然没有语法错误,但我只是挂在那里而不执行任何console.log语句。周围有点戳后,我改变,读取部分:( '没有找到地理数据' 匹配r.row( '地理数据')()) ''.filter 到: '.filter({地理:“没有找到地理数据”})' 这让代码开始运行,因为我看到的地理数据在控制台中记录的,但后来我得到了一个错误: 的RangeError:最大调用堆栈大小超过 这两段代码之间有什么区别,以及这个错误的原因是什么? –

+0

另外,你在哪里添加找到的行到to_update数组?对不起,只是通过代码尝试调试正在发生的事情,并且我注意到行可能没有被添加到该数组中。 –

+0

好吧,似乎RangeError是因为地图不能接受巨大的数组。因此,无论它需要分解成更小的子数组,还是需要在for循环中处理 – deontologician