Bookshelf一对一关联查询报错:books未在模型中定义
问题场景
按照Bookshelf官方一对一关联教程创建了Book与Summary模型:
Book模型通过hasOne关联SummarySummary模型通过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)
错误原因
- 关联名称不匹配:
Summary模型中定义的关联方法是book()(单数),但路由查询时用了withRelated: ['books'](复数),Bookshelf会严格匹配模型中定义的关联方法名。 - 重复初始化Bookshelf实例:每个模型单独初始化Bookshelf,导致模型之间的关联上下文隔离,无法识别彼此。
- 异步代码混用:同时使用
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

