【问题标题】:MongoDB with Mongoose - Find only certain child documentsMongoDB with Mongoose - 仅查找某些子文档
【发布时间】:2016-04-22 23:22:26
【问题描述】:

MongoDB 3.0.7 和 Mongoose 4.3.4。

架构:

var schema = new mongoose.Schema({
    confirmed: { type: Boolean, default: false },
    moves: [new mongoose.Schema({
        name: { type: String, default: '' },
        live: { type: Boolean, default: true }
    })]
});
mongoose.model('Batches', schema);

查询:

var Batch = mongoose.model('Batches');
var query = {
    confirmed: true,
    moves: {
        $elemMatch: {
            live: true
        }
    }
};
Batch.find(query).exec(function(err, batches){
    console.log('batches: ', batches);
});

我需要返回 confirmed 的所有批次,以及返回的批次中的所有移动 live

目前,上面只返回 confirmed 批次(这是我想要的),但 all 每个返回批次中的 moves (这不是我想要的) .所以live 标志的移动限制不起作用。

如何限制返回的子文档..?

理想情况下,我希望将控制query 中返回的数据的所有内容都传递给find,而不必在Batch 上调用更多方法。

【问题讨论】:

    标签: javascript mongodb mongoose


    【解决方案1】:

    对于支持 MongoDB 服务器 3.2.x 的 Mongoose 版本 >=4.3.0,您可以使用带有聚合框架的 $filter 运算符来限制/选择要返回的移动数组的子集指定的条件。这将返回一个数组,其中仅包含与条件匹配的元素,因此您将在 $project 阶段使用它来根据上述过滤器修改移动数组。

    下面的例子展示了如何去做:

    var Batch = mongoose.model('Batches'),
        pipeline = [
            {
                "$match": { "confirmed": true, "moves.live": true }
            },
            { 
                "$project": {
                    "confirmed": 1,
                    "moves": {
                        "$filter": {
                             "input": "$moves",
                             "as": "el",
                             "cond": { "$eq": [ "$$el.live", true ] }
                         }
                    }
                }
            }
        ];
    
    Batch.aggregate(pipeline).exec(function(err, batches){
        console.log('batches: ', batches);
    });
    

    或使用流畅的 aggregate() API 管道构建器:

    Batch.aggregate()
         .match({
             "$match": { "confirmed": true, "moves.live": true }
         })
         .project({
             "confirmed": 1,
             "moves": {
                 "$filter": {
                      "input": "$moves",
                      "as": "el",
                      "cond": { "$eq": [ "$$el.live", true ] }
                 }
             }
         })
         .exec(function(err, batches){
            console.log('batches: ', batches);
         });
    

    对于支持 MongoDB 服务器 >=2.6.x 的 Mongoose 版本 ~3.8.8, ~3.8.22, 4.x,您可以使用 $map$setDifference 的组合过滤掉错误值运营商:

    var Batch = mongoose.model('Batches'),
        pipeline = [
            {
                "$match": { "confirmed": true, "moves.live": true }
            },
            { 
                "$project": {
                    "confirmed": 1,
                    "moves": {
                        "$setDifference": [
                             {
                                 "$map": {
                                     "input": "$moves",
                                     "as": "el",
                                     "in": {
                                         "$cond": [
                                             { "$eq": [ "$$el.live", true ] },
                                             "$$el",
                                             false
                                         ]
                                     }
                                 }
                             },
                             [false]
                         ]
                     }
                }
            }
        ];
    
    Batch.aggregate(pipeline).exec(function(err, batches){
        console.log('batches: ', batches);
    });
    

    【讨论】:

      【解决方案2】:

      查询不限制实时标志的移动。查询内容为:找到所有已确认且至少包含一个实时移动的批次

      有 2 个选项可以仅检索实时移动:检索所有移动和filter 数组客户端;或 map-reduce 它在服务器端 - 展开所有动作,过滤实时动作,并按文档 ID 分组。

      前者实现起来更简单,但会导致客户端的数据传输、cpu 和内存消耗更多。后者效率更高,但实现起来有点复杂 - 如果您期望响应中超过 16Mb,则需要使用临时集合。

      【讨论】:

        【解决方案3】:

        您可以使用聚合框架的$unwind 方法将它们拆分为单独的文档,这里是示例代码。

        Batches.aggregate(
            { $match: {'confirmed': true, 'moves.live': true}}, 
            {$unwind: '$moves'},
            {$project: {
                    confirmed: 1
                    name: '$moves.name',
                    live:'$moves.live'
                }
            }, function(err, ret){
        })
        

        【讨论】:

          猜你喜欢
          • 2017-04-15
          • 2014-01-06
          • 2020-08-02
          • 2014-11-27
          • 2014-02-04
          • 2013-02-06
          • 1970-01-01
          • 1970-01-01
          • 2017-03-07
          相关资源
          最近更新 更多