MongoDB with Mongoose - 仅查找某些子文档

MongoDB with Mongoose - Find only certain child documents

本文关键字:文档 查找 with Mongoose MongoDB      更新时间:2023-09-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批次(这是我想要的(,但返回的每个批次中的所有moves(这不是我想要的(。因此,live标志对移动的限制是行不通的。

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

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

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

以下示例显示了如何执行此操作:

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 Server >=2.6.x 的 Mongoose 版本~3.8.8, ~3.8.22, 4.x,您可以使用 $map $setDifference 运算符的组合来过滤掉 false 值:

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 个选项可以仅检索实时移动:检索所有移动,并过滤数组客户端;或 map-reduce it 服务器端 - 展开所有移动,过滤实时移动,并按文档 ID 分组。

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

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

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