You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bookshelf一对一关联查询报错:books未在模型中定义

问题解决:Bookshelf一对一关联查询报错“books is not defined on the model”

问题场景

按照Bookshelf官方一对一关联教程创建了Book与Summary模型:

  • Book模型通过hasOne关联Summary
  • Summary模型通过belongsTo关联Book
    添加测试数据后,在Express路由中尝试通过Summary模型查询指定ID数据并关联查询书籍时,触发报错:

Error: books is not defined on the model.
at EagerRelation. (C:\Users\bitcot\work\nodejs\node_modules\bookshelf\lib\base\eager.js:50:15)
at EagerRelation.tryCatcher (C:\Users\bitcot\work\nodejs\node_modules\bluebird\js\release\util.js:16:23)
at EagerRelation.fetch (C:\Users\bitcot\work\nodejs\node_modules\bluebird\js\release\method.js:15:34)
at Child._handleEager (C:\Users\bitcot\work\nodejs\node_modules\bookshelf\lib\model.js:1526:56)

错误原因

  1. 关联名称不匹配:Summary模型中定义的关联方法是book()(单数),但路由查询时用了withRelated: ['books'](复数),Bookshelf会严格匹配模型中定义的关联方法名。
  2. 重复初始化Bookshelf实例:每个模型单独初始化Bookshelf,导致模型之间的关联上下文隔离,无法识别彼此。
  3. 异步代码混用:同时使用await和then,容易导致变量作用域问题(原代码中books变量在then回调外可能未正确赋值)。

修复步骤

1. 统一Bookshelf实例

创建单独的Bookshelf实例文件,所有模型共享该实例:

// data/bookshelf.js
const dbConfig = require('./db');
const bookshelf = require('bookshelf')(dbConfig);

module.exports = bookshelf;

2. 修正模型关联引用

更新Book和Summary模型,使用统一的Bookshelf实例,并确保关联模型被提前引入:

Book模型(model/book.js):

const bookshelf = require('../data/bookshelf');

const Book = bookshelf.model('Book', {
  tableName: 'books',
  summary() {
    return this.hasOne('Summary');
  }
});

module.exports = Book;

Summary模型(model/summary.js):

const bookshelf = require('../data/bookshelf');
// 提前引入Book模型,确保Bookshelf能识别关联
const Book = require('./book');

const Summary = bookshelf.model('Summary', {
  tableName: 'summaries',
  book() {
    return this.belongsTo('Book');
  }
});

module.exports = Summary;

3. 修正路由查询逻辑

将withRelated的关联名称改为单数'book',并统一使用try/catch处理异步逻辑:

// 路由文件
const express = require('express');
const router = express.Router();
const Summary = require('../../model/summary');

router.get('/', async (req, res) => {
  try {
    // 使用where方法替代直接实例化模型,更符合Bookshelf规范
    const summary = await Summary.where({ id: 1 }).fetch({ withRelated: ['book'] });
    res.json(summary.toJSON());
  } catch (err) {
    if (err instanceof Summary.NotFoundError) {
      res.send('empty response. :/');
      console.log('caught unhandled exception.. so happy :) ');
      console.log(err);
    } else {
      res.status(500).send('服务器错误');
      console.error(err);
    }
  }
});

module.exports = router;

验证结果

修复后重新启动服务,访问该路由即可成功获取Summary关联的Book数据,报错消失。

内容的提问来源于stack exchange,提问作者Ashutosh Soni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 16:55:25