Mongoose数据转JSON遇循环结构错误,求ng-table动态生成方案
解决方案:修复循环引用错误+自动适配ng-table动态表头
嘿,我来帮你搞定这两个问题:先是解决那个「循环结构转JSON」的报错,再实现自动提取表头、格式化数据并适配ng-table的需求!
1. 先搞定循环引用的TypeError
你遇到这个错误,是因为从Mongoose拿到的routput不是纯JavaScript对象,而是Mongoose Document实例——这些实例自带了和数据库连接、模型相关的属性(比如base、connections),形成了循环引用,直接用JSON.stringify就会炸。
解决方法有两种,选一种就行:
- 查询时直接返回纯对象:在Mongoose查询里加
.lean(),这样数据库返回的就是普通JS对象,没有额外的Mongoose属性:// 示例:查询时用lean() YourModel.find({/* 查询条件 */}).lean().exec((err, routpu) => { // 这里的routput就是纯JS对象数组,不会有循环引用 }); - 把已有的Document转成纯对象:如果已经拿到了Document实例,用
.toObject()或者.toJSON()转换:// 把Mongoose文档数组转成纯JS对象数组 const plainData = routpu.map(doc => doc.toObject());
2. 自动提取表头+格式化特殊字段(_id/日期)
接下来写一个通用函数,不管传入什么数据,都能自动提取表头,同时把_id转成字符串、日期转成YYYY-MM-DD格式:
function formatReportOutput(data) { // 处理空数据的情况 if (!Array.isArray(data) || data.length === 0) { return { headers: [], values: [] }; } // 自动提取表头:取第一个数据对象的所有键 const headers = Object.keys(data[0]); // 格式化每一行数据,处理_id和日期 const values = data.map(item => { return headers.map(key => { const value = item[key]; // 处理MongoDB的ObjectId if (key === '_id' && value?.toString) { return value.toString(); } // 处理ISODate,转成YYYY-MM-DD if (value instanceof Date) { return value.toISOString().split('T')[0]; } // 其他类型直接返回 return value; }); }); return { headers, values }; }
调用示例:
// 假设plainData是已经转成纯JS对象的数据 const formattedResult = formatReportOutput(plainData); // formattedResult.headers = ["_id", "INumber", "IID", "DateReceived"] // formattedResult.values = [["59920689253dfa0544f26b93", "535264", "25544825", "2017-08-14"]]
3. 适配ng-table实现自动渲染
现在把格式化后的数据传给AngularJS,动态生成ng-table的列和数据:
控制器代码
app.controller('ReportController', function($scope, $http, ngTableParams) { // 从后端接口获取格式化后的数据(或者直接在前端处理) $http.get('/routes/data') .then(function(response) { const { headers, values } = response.data; // 把二维数组转成ng-table需要的对象数组:每个元素是{表头: 值}的结构 $scope.tableData = values.map(row => { const rowObj = {}; headers.forEach((key, index) => { rowObj[key] = row[index]; }); return rowObj; }); // 自动生成ng-table的列配置 $scope.tableColumns = headers.map(key => ({ title: key, // 表头显示的文字 field: key // 对应数据对象的属性名 })); // 初始化ng-table参数 $scope.tableParams = new ngTableParams({ page: 1, // 默认页码 count: 10 // 默认每页条数 }, { dataset: $scope.tableData }); }); });
模板代码
<div ng-controller="ReportController"> <table ng-table="tableParams" class="table table-striped"> <tr ng-repeat="row in $data"> <td ng-repeat="col in tableColumns" data-title="col.title" sortable="col.field"> {{ row[col.field] }} </td> </tr> </table> </div>
这样不管你传入什么结构的数据库数据,都能自动提取表头、格式化特殊字段,然后在ng-table里自动渲染,完全不需要硬编码表头!
内容的提问来源于stack exchange,提问作者realme
相关产品推荐
相关产品推荐

