findOne 操作后变量未定义 mongodb

variable undefined after findOne operation mongodb

我正在尝试制作一个 API,它利用 2 个数据库生成罚款。这是代码:

router.get("/generateFine/:bookingID/:currDate", function (req, res, next) {
    var currDate,
        returnDate,
        fine,
        totalFine = 0;
    Booking.findOne({ _id: req.params.bookingID }).then(function (booking) {
        Car.findOne({ _id: booking.carID }).then(function (car) {
            currDate = Date.parse(req.params.currDate) / 1000 / 3600 / 24;
            returnDate = Date.parse(booking.bookingDates[1]) / 1000 / 3600 / 24;
            fine = car.fine;
            if (currDate > returnDate) {
                totalFine = fine * (currDate - returnDate);
            }
            console.log(totalFine);
            // res.send(totalFine);
        });
        console.log("totalFine is " + totalFine);
        // res.send(totalFine);
    });
});

以下是代码中使用的两个 Schemas: 预订架构:

{
    "_id" : ObjectId("621bf46602edf12942f0d5c9"),
    "carID" : "621b87af70c150da70b1dabf",
    "bookingDates" : [ 
        "2022-03-05", 
        "2022-03-06"
    ],
}

汽车架构:

{
    "_id" : ObjectId("621b87af70c150da70b1dabf"),
    "name" : "Toyota",
    "rate" : 60,
    "fine" : 10,
    "datesBooked" : [ 
        {
            "from" : "2022-03-05",
            "to" : "2022-03-06"
        }, 
        {
            "from" : "2022-03-07",
            "to" : "2022-03-08"
        }, 
        {
            "from" : "2022-03-09",
            "to" : "2022-03-10"
        }
    ],
    "__v" : 0
}

我想return生成的罚款给用户。当我尝试发送结果时,它抛出一个错误。第一个控制台日志打印正确的结果,但第二个控制台日志打印 0。另外,我怎样才能在不出错的情况下发送结果。 已经谢谢了!

您可以使用 $lookup 聚合管道阶段来包含在 carID 字段上匹配的汽车文档,创建额外的计算字段,这将帮助您在使用必要的聚合时获得总罚款运算符。

基本上你需要运行一个聚合管道如下:

const mongoose = require('mongoose');

router.get('/generateFine/:bookingID/:currDate', async function (req, res, next) {
    const currDate = new Date(req.params.currDate);
    const [{ totalFine }] = await Booking.aggregate([
        { $match: { _id: mongoose.Types.ObjectId(req.params.bookingID) }},
        { $lookup: {
            from: 'cars', // or from: Car.collection.name
            let: { carId: { $toObjectId: '$carID' } }, // convert the carID string field to ObjectId for the match to work correctly
            pipeline: [ 
                { $match: {
                    $expr: { $eq: [ '$_id', '$$carId' ] }
                } }
            ],
            as: 'car'
        } },
        { $addFields: { 
            car: { $arrayElemAt: ['$car', 0 ] }, // get the car document from the array returned above
            returnDate: {
                $toDate: { $arrayElemAt: ['$bookingDates', 1 ]}
            }
        } },
        // compute the overdue days 
        { $addFields: { 
            overdueDays: {
                $trunc: {
                    $ceil: {
                        $abs: {
                            $sum: { 
                                $divide: [
                                    { $subtract: [currDate, '$returnDate'] },
                                    60 * 1000 * 60 * 24
                                ] 
                            }
                        }
                    }
                }
            }
        } },
        { $project: { // project a new field
            totalFine: { 
                $cond: [
                    { $gt: [currDate, '$returnDate'] }, // IF current date is greater than return date
                    { $multiply: ['$car.fine',  '$overdueDays'] }, // THEN multiply car fine with the overdue days
                    0 // ELSE total fine is 0
                ]
            }
        } }
    ]).exec();

    console.log("totalFine is " + totalFine);
    // res.send(totalFine);
});