【问题标题】:Client-side asynchronous join of database tables数据库表的客户端异步连接
【发布时间】:2015-10-25 15:25:18
【问题描述】:

我整天都在试图解决这个问题。

我正在尝试从 sqlite 数据库、angularJS 应用程序中提取实体树,使用 nodejs 作为 shim 运行从客户端生成的 SQL 查询。我也在使用 underscore.js。

我可以通过使用连接将实体展平为类似表格的结构(不包含其他对象的对象数组)并将行“膨胀”到嵌套对象和数组客户端,但我想了解承诺。我本可以将 Spring 与 Hibernate 和 JPA 一起使用,将 JSON 从服务器传递到服务器,但这是一个实验。我知道它在很多层面上都不是最优的。

问题

tableA 包含 A 类型的实体。对于表 B 和 C。数据库中的关系是:A 有一组 B。每个 B 都与 C 配对。所以,如果我使用 Hibernate 和 Spring,我可以问对于 A,服务器会响应一个 A 数组,每个项目都包含一个 B 数组,而 Avery 包含一个 C。

我的实现

我希望函数'getAObjectDeep'返回一个promise,当我在promise上调用success(callback)时,回调传递一个A类型的实体列表,每个实体都包含一个B类型的实体数组,其中又包含 C 类型的匹配实体。

这是我写的代码,它不起作用。问题是,当我在第二个承诺中调用 $q.all 时,A 类型的所有实体都丢失了,并且响应中填充了 B 类型的实体数组数组,当我在第三个承诺,所有类型 B 的实体都丢失了,响应中填充了“未定义”数组。 我无法控制 $q.all 的输出,将前一个 Promise 的值传递给下一个 Promise,并使用从数据库中获得的新行进行丰富。

var queryDb = function(query) {
    return $http.get('/', {params: {sql: query}});
};

var getAObjectDeep = function(start, end) {
    return queryDb('SELECT * FROM tableA WHERE tableA.date >= \'' + start + '\' AND tableA.date <= \'' + end + '\' ORDER BY date DESC;')
    .then(function(response) {
        return $q.all(_.map(response.data, function(entityA) {
            return _.extend(entityA, queryDb('SELECT * FROM tableB WHERE idEntityA=' + entityA.id + ';'));
        }));
    })
    .then(function(response) {
        return $q.all(_.map(response, function(r) {
            var entityB = r.data;
            return _.extend(entityB, queryDb('SELECT * FROM tableC WHERE id=' + entityB.idObjB));
        }));
    });
}

【问题讨论】:

  • 为什么不使用JOIN 而不是N+1 查询?
  • 我不认为 r.data 存在,因为你已经映射了上一个代码块中的结果 r 应该是当前的下划线对象
  • 我认为您仍然应该向服务器询问完整的嵌套响应 - 减少流量。不要在客户端生成 SQL 查询并在服务器上执行它们。你仍然会使用与 promises 相同的代码,但在 nodejs 中不是 angular。

标签: angularjs node.js promise


【解决方案1】:

不要忘记queryDb() 在所有三种情况下都会返回一个promise,并且响应只能通过promise 方法访问,而不是直接访问。

queryDb() 的第一次使用显示了正确的模式:

queryDb(...)
.then(function() {
    ...
});

但第二个和第三个用途似乎假设一个数组 - 在任何情况下_.extend() 将操作的东西。

据我所知,您需要将最里面的两个表达式“由内向外”,并引入一个.then()

var getAObjectDeep = function(start, end) {
    return queryDb('SELECT * FROM tableA WHERE tableA.date >= \'' + start + '\' AND tableA.date <= \'' + end + '\' ORDER BY date DESC;')
    .then(function(response) {
        return $q.all(_.map(response.data, function(entityA) {
            return queryDb('SELECT * FROM tableB WHERE idEntityA=' + entityA.id + ';').then(function(response2) {
                return _.extend(entityA, response2);
            });
        }));
    })
    .then(function(response) {
        return $q.all(_.map(response, function(r) {
            var entityB = r.data; //???
            return queryDb('SELECT * FROM tableC WHERE id=' + entityB.idObjB).then(function(response3) {
                return _.extend(entityB, response3);
            });
        }));
    });
}

从 async/promise 的角度来看,原始代码的这种转换(更)有意义。

“加入”逻辑与问题中的逻辑相同。除了@vbranden 指出的var entityB = r.data 可能不正确外,没有尝试对其进行验证;如果不起作用,请尝试var entityB = r

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-26
    • 2016-05-24
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 2020-03-22
    • 1970-01-01
    • 2014-04-07
    相关资源
    最近更新 更多