2015-05-19 76 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