我正在尝试使用简单的Express API学习MongoDB . API可以很好地获取单个集合,但是当我尝试使用mongoose ref
将多个集合组合到一个模式中时,我得到一个仅包含 _id
字段的json响应 .
以下是Mongoose中的两个模式:
var LinkSchema = require('./link.js');
var MyInfoSchema = new Schema({
name: String,
title: String,
links: [ LinkSchema ]
});
var AboutSchema = new Schema({
img: String,
description: String
});
这些在 endpoints 分别调用它们时工作正常 .
我希望有一个 endpoints 将这两个集合组合成一个json响应 . 所以,我用 ref
制作了这个模型
var MyInfoSchema = require('./myinfo.js');
var AboutSchema = require('./about.js');
var AllDataSchema = new Schema({
myinfo: {
type: mongoose.Schema.ObjectId,
ref: 'MyInfoSchema'
},
about: {
type: mongoose.Schema.ObjectId,
ref: 'AboutSchema'
}
});
My Express API路线如下所示
var router = express.Router();
router.route('/')
.get(function(request, response){
var data = new AllData();
// add myinfo
MyInfo.findOne(function(error, info){
data.myinfo = info;
console.log(data); // this gives an id
});
// add about
About.findOne(function(error, about){
data.about = about;
});
console.log(data); // this prints nothing
response.json(data);
});
但是,我得到的json响应只是 _id
{
“_id”:“59bfed783f0ba490a34c9ce9”
}
为什么没有填充响应?
我尝试登录到控制台 . 当我把日志放在 findOne()
里面时,我得到一个像这样的对象
{ _id: 59bfed783f0ba490a34c9ce9,
myinfo: 59b1ad02d551330000000002 }
当我将log语句放在find函数之外且在 response.json()
之前时,我什么也得不到 . 这是为什么? data
应该还在范围内,不是吗?
Edit:
正如@Mikey在答案中所建议的,我已经重构使用Promises . 这越来越近,但有两个问题 . 1.缺少每个集合的密钥,以及2.它返回根结构的数组而不是对象 .
这是更新
.get(function(request, response){
var data = new AllData();
var p1 = MyInfo.findOne().exec(),
p2 = Navigation.findOne().exec(),
p3 = About.findOne().exec(),
p4 = Contact.findOne().exec();
Promise.all([p1, p2, p3, p4]).then(function(data) {
data.myinfo = data[0];
data.navigation = data[1];
data.about = data[2];
data.contact = data[3];
response.json(data);
});
});
这就是回应
[
{
"_id": "59b1ad02d551330000000002",
"title": "Television Tester",
"name": "Walter P. K.",
"__v": 0,
"links": [
{
"name": "...",
"url": "...",
"_id": "59b1ad02d551330000000004"
},
{
"name": "more...",
"url": "more...",
"_id": "59b1ad02d551330000000003"
}
]
},
{
"_id": "59b2e606103ace0000000003",
"__v": 1,
"links": [
{
"name": "About",
"url": "#",
"_id": "59b2e62d103ace0000000009"
},
{
"name": "Stuff",
"url": "#",
"_id": "59b2e62d103ace0000000008"
},
{
"name": "Contact",
"url": "#",
"_id": "59b2e62d103ace0000000007"
}
]
}
...
]
它应该是这样的
{
myinfo: {}.
navigation: {},
about: {},
contact: {}
}
3 回答
Mongoose操作是异步的 . 您需要在发送响应之前等待所有操作完成 .
您可以嵌套您的操作
或使用承诺(我认为这是这样的)
findOne 是异步的,因此您的控制台日志在 findOne 回调之前运行 .
你可能正在寻找更像这样的东西,它将查询你的'AllData'集合并用'myinfo'和'about'的引用文件替换存储的id:
我能够通过其他回答者的有用建议解决问题 . 感谢您指出
find()
和promises的异步性质 . 我需要使其工作的是使用普通的JS对象作为响应结构(而不是Mongoose Schema),以及一些变量名称清理 . 在Mikey的回答和我对问题的编辑中,返回的响应和console.log数组实际上是promises数组(即p1,p2,p3等的值),而不是我想要返回的数据结构 .这是工作代码: