从rethinkdb数据库获取数据,操纵所述数据,然后使用操作的文档更新数据库

时间:2015-05-19 16:29:26

标签: javascript node.js rethinkdb

我正在寻找一个get,在结果上运行一个函数,它将通过更新字段进行一些操作,然后将该文档放回数据库中。真的我的问题是能够将多个数据库调用链接在一起。过去一周左右,我一直在努力解决这个问题。任何建议表示赞赏,谢谢。

这是我到目前为止所尝试的但我收到错误:

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);
            });
          }
        })
      }
    })
  }

2 个答案:

答案 0 :(得分:1)

这是一个可能的解决方案,它使用promises来组织代码。

// 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 ...
    })

在此代码段中,您使用do内的 内的JS函数。你不能这样做。请记住,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});
 })

答案 1 :(得分: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
        });
};
告诉我,我没有运行这个,所以可能存在语法错误和事情