Mongoose 返回子文档未定义

问题描述 投票:0回答:1

我有《Getting MEAN》一书中的 Express 应用程序示例。我正在使用 Mongoose 连接到 Mongodb。这是文件


{
  "_id": {
    "$oid": "65537eb149dd64103a4b7950"
  },
  "name": "Starcups",
  "address": "125 High Street, Reading, RG6 1PS",
  "rating": 3,
  "facilities": [
    "Hot drinks",
    "Food",
    "Premium wifi"
  ],
  "coords": [
    -0.9690884,
    51.455041
  ],
  "openingTimes": [
    {
      "days": "Monday - Friday",
      "opening": "7:00am",
      "closing": "7:00pm",
      "closed": false
    },
    {
      "days": "Saturday",
      "opening": "8:00am",
      "closing": "5:00pm",
      "closed": false
    },
    {
      "days": "Sunday",
      "closed": true
    }
  ],
  "reviews": [
    {
      "author": "Lekan Yusuf",
      "id": {
        "$oid": "6560c0dfadc556388f6b8e93"
      },
      "rating": 4,
      "timestamp": {
        "$date": "1992-06-11T23:00:00Z"
      },
      "reviewText": "Good wifi, moderate coffee"
    },
    {
      "author": "Lekan Yusuf",
      "id": {
        "$oid": "6563c6c0d8b148207dcc9817"
      },
      "rating": 4,
      "timestamp": {
        "$date": "1992-06-11T23:00:00Z"
      },
      "reviewText": "Good wifi, moderate coffee"
    }
  ]
}



我有这条路线:

var express = require('express');
var router = express.Router();
var ctrlReviews =require('../controllers/reviews');


//reviews routes
router.get('/locations/:locationid/reviews/:reviewid', ctrlReviews.reviewsReadOne);
router.post('locations/:locationid/reviews', ctrlReviews.createReview);
router.put('locations/:locationid/reviews/reviewid', ctrlReviews.reviewsUpdateOne);
router.delete('locations/:locationid/reviews/reviewid', ctrlReviews.reviewsDeleteOne);

这是控制器代码:

module.exports.reviewsReadOne = function(req, res){
    console.log('in ReviewsReadOne');
        
    if(req.params && req.params.locationid && req.params.reviewid){
        console.log('locationid: '+ req.query.locationid + ' reviewid: '+ req.query.reviewid);
        Loc.findById(req.query.locationid, 'name reviews').exec(
            function(err,location){
                var response, review;
                if(!location){
                    sendJsonResponse(res, 404, {"message": "locationid not found"});
                    return;   
                } else if (err){
                    sendJsonResponse(res, 404, err);
                    return;
                }
                console.log('location just before "if(location.reviews && location.reviews.length >0)"\n' + location);
                console.log('\n reviews: '+ location.reviews);
                
                if(location.reviews && location.reviews.length >0){

                    review = location.reviews.id(req.params.reviewid);
                    
                    if(!review){
                        sendJsonResponse(res, 400, {"message":"Review id not found"});
                    } else {
                        console.log('review ' + review)
                        response ={
                            location:{
                                name: location.name,
                                id: req.query.id
                            },
                            review:review
                        };
                        sendJsonResponse(res, 200, response);

                    }
                } else {
                    sendJsonResponse(res, 400, {message:"Not found, locationid and reviewid are both required"});
                }

            }
        );

    } else{
        sendJsonResponse(res, 400, {"message": "No location id and or review id"});
        return;
    }
    
}

当我使用现有的 locationid 和 reviewid 测试 Postman 的 API 时,它给出:

{
    "message": "Not found, locationid and reviewid are both required"
}

VSCode 终端给出以下输出:

in ReviewsReadOne
locationid: 65538583fc3b3ac2c0b83a8d reviewid: 6563c74141216ec9d9ec7c38
location just before "if(location.reviews && location.reviews.length >0)"
{
  _id: new ObjectId("65538583fc3b3ac2c0b83a8d"),
  name: 'Starfi',
  reviews: [
    {
      author: 'Subomi ogunderu',
      id: new ObjectId("6563c74141216ec9d9ec7c38"),
      rating: 3,
      timestamp: 1995-08-11T23:00:00.000Z,
      reviewText: 'Excellent wifi and the food is great'
    }
  ]
}

 reviews: undefined

GET /api/locations/locationid/reviews/reviewid?locationid=65538583fc3b3ac2c0b83a8d&reviewid=6563c74141216ec9d9ec7c38 400 566.482 ms - 66


显然,定位文档是检索到了,但是测试,

if(location.reviews && location.reviews.length >0)

失败了,这似乎就是我得到的原因

reviews: undefined

在终端中。

请问为什么评论未定义,我该如何解决这个问题。

mongodb mongoose schema undefined subdocument
1个回答
0
投票

在此行:

review = location.reviews.id(req.params.reviewid)

您似乎试图使用

id()
,就好像它是
location.reviews
数组的方法一样。不幸的是,猫鼬如果不是这样设计的,因为
location.reviews
MongooseArray
类型,它的方法数量有限。

值得庆幸的是,mongodb 有一系列很好的运算符可供选择,您可以使用它们来查找和选择文档的特定属性,这将使您的代码更易于阅读。例如,

$elemMatch
运算符可以让您匹配数组中的元素,如果与
$
位置运算符结合使用,意味着您可以选择仅投影该元素。

您可以使用此代码,该代码采用现代

async/await
模式,利用
try/catch
块进行更清晰的错误处理:

module.exports.reviewsReadOne = async function(req, res){ //< Mark function as async
    console.log('in ReviewsReadOne');
    if(req.params && req.params.locationid && req.params.reviewid){
        console.log('locationid: '+ req.query.locationid + ' reviewid: '+ req.query.reviewid);
        try{
            const location = await Loc.findOne({ //< await the async query
                _id: req.query.locationid,
                reviews: {
                    $elemMatch : {
                        _id: req.query.reviewid
                    }
                }
            }, {
                name: 1, //< Output location name
                'reviews.$': 1 //< Output the matching review
            });
            if(!location){ //< location will be null if no matches
                sendJsonResponse(res, 404, {"message": "Document not found"});
                return;
            }
            sendJsonResponse(res, 200, location);
        } catch (err) {
            console.log(err);
            sendJsonResponse(res, 500, {"message": "Error on server. Check log."});
            return;
        }
    } else{
        sendJsonResponse(res, 400, {"message": "No location id and or review id"});
        return;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.