首页 文章

猫鼬没有填充json

提问于
浏览
0

我正在尝试使用简单的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 回答

  • 1

    Mongoose操作是异步的 . 您需要在发送响应之前等待所有操作完成 .

    您可以嵌套您的操作

    router.route('/').get(function(request, response){
        var data = new AllData();
    
        MyInfo.findOne(function(err, info) {
            data.myinfo = info;
            About.findOne(function (err, about){
                data.about = about;
                response.json(data);
            });
        });
    });
    

    或使用承诺(我认为这是这样的)

    router.route('/').get(function(request, response){
        var data = new AllData();
    
        var p1 = MyInfo.findOne().exec(),
            p2 = About.findOne().exec();
    
        Promise.all([p1, p2]).then(function(data) {
            data.myinfo = data[0];
            data.about = data[1];
            response.json(data);
        });
    });
    
  • 1

    findOne 是异步的,因此您的控制台日志在 findOne 回调之前运行 .

    你可能正在寻找更像这样的东西,它将查询你的'AllData'集合并用'myinfo'和'about'的引用文件替换存储的id:

    AllData.find()
      .populate('myinfo about')
      .exec(function(error, docs) {
        console.log(docs)
        response.json(docs)
      });
    
  • 1

    我能够通过其他回答者的有用建议解决问题 . 感谢您指出 find() 和promises的异步性质 . 我需要使其工作的是使用普通的JS对象作为响应结构(而不是Mongoose Schema),以及一些变量名称清理 . 在Mikey的回答和我对问题的编辑中,返回的响应和console.log数组实际上是promises数组(即p1,p2,p3等的值),而不是我想要返回的数据结构 .

    这是工作代码:

    router.route('/')
        .get(function(request, response){
    
            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(docs) {
                var data = {};
                console.log(docs);
                data.myinfo = docs[0];
                data.navigation = docs[1];
                data.about = docs[2];
                data.contact = docs[3];
                response.json(data);
            });
        });
    

相关问题