【问题标题】:Sails 0.10 association fails to populateSails 0.10 关联无法填充
【发布时间】:2014-04-11 02:01:32
【问题描述】:

我正在使用sails@0.10.0-rc4 中的自定义适配器来支持关联,但我无法让它们与我的适配器一起工作。我的配置是文章和统计数据之间的一对多关联。我的模型和适配器设置如下:

// api/models/article.js
module.exports = {
  connection: ['myadapter'],
  tableName: 'Knowledge_Base__kav',
  attributes: {
    KnowledgeArticleId: { type: 'string', primaryKey: true }
    stats: {
      collection: 'stats',
      via: 'parentId'
    } 
  }

// api/models/stats.js
module.exports = {
  connection: ['myadapter'],
  tableName: 'KnowledgeArticleViewStat',
  attributes: {
    count: 'integer',
    ParentId: {
      model: 'article'
    }
  }
}


// adapter.js  
find: function(connectionName, collectionName, options, cb) {  
  console.dir(options)
  // output
  // {where: null} 
  db.query(options, function(err, res)) {
    cb(err, res)
  }
}

但是,当我尝试使用Article.find().populate('stats').exec(console.log()) 进行填充时,我的适配器会获得{where: null} 作为选项,而我希望它接收{where: {parentId: [<some-article-id>]}}。它返回一个文章列表给我,但应该从另一个模型(统计)填充的字段只是一个空列表。

我觉得这与我的适配器没有获得正确的 where 参数来搜索主键上的相关模型有关。为了进一步测试这一点,我使用sails-mongo 适配器设置了一个测试一对多关系。在这种情况下,适配器确实收到了我预期的参数,并且关联工作正常。

有人知道为什么.populate('stats') 不会向我的适配器发送正确的“where”参数吗?

更新 3/7

因此,似乎关联中发生的事情是 SomeModel.find() 将命中适配器一次,然后 .populate('othermodel') 使用第一个请求的主键再次命中适配器。然后将两者的结果结合在一起。就我而言,由于某种未知原因,没有发生对适配器的第二次攻击。

更新

最初的问题与下面的 cmets 中提到的属性命名错误有关。但是,particlebanana 提到的最终填充步骤似乎仍然存在一些问题:

最后一步:从所有返回的查询操作中取出所有查询结果 并在内存中组合它们以建立一个可以返回的结果集 执行回调。

我看到所有必需的查询现在都在触发,但它们实际上未能填充别名。下面是调用,以 gist 的形式添加了一些调试输出,以便于使用:https://gist.github.com/jasonsims/9423170

【问题讨论】:

    标签: node.js sails.js waterline


    【解决方案1】:

    看来您的方向是正确的!操作集的建立方式,文章上的.find() 应该使用第一个日志(空位置)运行,第二个查询应该使用日志中的 parentId 条件运行。第二个查询没有运行,因为当您没有从第一个查询返回任何内容时,它无法构建主键 parentId 数组。

    简答:您需要在find 回调中返回一些内容才能查看第二个日志,这应该符合您的预期标准。

    查询生命周期如下所示:

    • 检查所有查询片段是否都在同一个连接上,如果没有,则确定哪些查询将在哪些连接上运行
    • 对于单个连接上的所有查询,检查适配器是否支持本机联接(具有 .join() 方法,如果支持,您可以向下传递条件并让适配器处理联接。
    • 如果未定义本地连接方法,则运行“父”操作(在本例中为 Article.find()
    • 使用父操作的结果为需要运行的任何种群建立标准。 (您的条件中的 parentId 数组)并运行子结果。
    • 从所有返回的查询操作中获取所有查询结果,并在内存中组合它们以构建一个结果集,您可以在 exec 回调中返回。

    希望对大家有所帮助。把你的 repo 的 url 发给我,我会查看它,如果它能够开源,如果你遇到任何问题,可以提供更多帮助。

    【讨论】:

    • 谢谢!这只是上面的一个坏例子。实际上,我正在使用我最初的查找结果执行回调。我还没有开源新的适配器,因为它还没有准备好迎接黄金时段,但我可以将你添加到 repo 中,以便你查看。 github.com/jasonsims/sails-forcedotcom
    • 所以第二个查询没有命中的问题是因为我的模型将primaryKey定义为knowledgeArticleId,但是执行父操作后salesforce API返回的是KnowledgeArticleId(第一个字符大写)。我认为在尝试建立第二个操作的标准时,这种差异会导致问题。
    • 然而,现在的问题是第二个操作的结果没有进入组合结果。我可以看到这两个查询都成功执行并找到了结果,但是应该填充的字段(统计信息)仍然是一个空列表。
    【解决方案2】:

    总结一下,这里发生了多个导致关联无法填充的问题:

    1. 自定义主键
      使用自定义主键连接模型中的数据时,水线出现问题。 @particlebanana8eff54b 中修复了这个问题,它应该包含在水线的下一个 rc (waterline@0.10.0-rc5) 中。
    2. 格式错误的 SOQL 查询
      当 waterline 第二次查询适配器以获取子行时,它使用{ foreignKey: [ value ] } 这样做。由于该值是一个列表,因此 jsforce 错误地生成了 SOQL 查询,因为它期望所有列表值都伴随有 $in$nin 运算符。我在 github/jsforce#9 中解决了这个问题,它现在包含在 jsforce@1.1.2 中。
    3. 模型属性区分大小写
      我项目中的模型是在 snakeCase 中定义的,但来自 Salesforce 的 json 响应使用的是 EveryWordCapitalized。这会导致水线中的一对多连接在运行_.uniq(childRows, pk) 时将许多子记录减少到一个。由于模型定义了pk == id,但从 Salesforce 返回的实际值是pk == Id,因此对 uniq 的调用会清除除一个之外的所有子记录。我不完全确定这是否应该是水线错误,但修复模型属性定义中的大写解决了这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-03
      • 1970-01-01
      • 2015-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多