猫鼬过滤器嵌套数组

时间:2019-07-02 15:36:24

标签: node.js mongodb mongoose mongoose-schema

我想返回一个给定shortName的餐厅,并过滤其数组menuEntries,使其仅包含将字段isAvailable设置为true的菜单项。

这是我的模式:

var restaurantSchema = new mongoose.Schema({
    shortName: String,
    fullName: String,
    address: String,
    logoImageUrl: String,
    description: String,
    location: {
        type: { type: String },
        coordinates: [Number]
    },
    menuEntries: [{
        name: String,
        description: String,
        isAvailable: Boolean
    }],
    updatedAt: {type : Date}
});

restaurantSchema.index({ 'location': '2dsphere' });

mongoose.model('Restaurant', restaurantSchema, 'Restaurants');

我正在使用以下查询,但它仍返回将isAvailable设置为false的菜单项:

Restaurant
    .findOne({
        shortName: shortName,
        menuEntries: { $elemMatch: { isAvailable: { $eq: true } } }
    }, function(error, restaurant) {
        if (error) {
            returnJsonResponse(response, 500, {
                'message': error
            });
        } else if (!restaurant) {
            returnJsonResponse(response, 404, {
                'message': 'Restaurant with name ' + shortName + ' doesn\'t exist'
            });
        } else {
            returnJsonResponse(response, 200, restaurant);
        }
    });

编辑

它也不适用于以下代码:

Restaurant
    .findOne({
        shortName: shortName
    })
    .elemMatch('menuEntries', {'isAvailable': true})
    .exec(function(error, restaurant) {
        if (error) {
            returnJsonResponse(response, 500, {
                'message': error
            });
        } else if (!restaurant) {
            returnJsonResponse(response, 404, {
                'message': 'Restaurant with name ' + shortName + ' doesn\'t exist'
            });
        } else {
            returnJsonResponse(response, 200, restaurant);
        }
    });

我正在使用猫鼬^ 5.6.2 MongoDB 3.6.9 。我在做什么错了?

2 个答案:

答案 0 :(得分:0)

$elemMatch不是您想要的。您尝试过滤文档内部的数组,而不是基于数组的文档列表。为了完成您想要实现的目标,您必须使用聚合和$filter operator

请查看the official example,但我认为您的代码应如下所示:

Restaurant.aggregate([
   {
      $project: {
         menuEntries: {
            $filter: {
               input: "$menuEntries",
               as: "entry",
               cond: { $$eq: [ "$$entry.price", true ] }
            }
         },
        shortName: 1,
        fullName: 1,
        address: 1,
        logoImageUrl: 1,
        description: 1,
        location: 1,
        updatedAt: 1
      }
   }
])

请注意,$project要求您manually include all the other fields

答案 1 :(得分:0)

viewRestaurant: (request, callback) => {
        let aggrQuery = [
            {
                '$match': { "shortName": request }
            },
            { $unwind: "$menuEntries" },
            { '$match': { 'menuEntries.isAvailable': true } },
        ]
        restaurantQuery.aggregate(aggrQuery).exec((err, data) => {
            if (err) {
                callback(err, null)
            }
            else {
                callback(null, data)
            }
        })
    },

router.post('/view-restaurant',(req,res)=>{
    var request = req.body.shortName;
    restaurantController.viewRestaurant(request,(err,data)=>{
        if(err) throw err;
        res.json(data);
    })
})