有问题选择文件并在其subco上应用过滤器

时间:2016-02-02 07:13:10

标签: mongodb mongoose mongodb-query

所以这是交易,我使用的是Mongoose,我有一个PollOptionSchema,里面有选民名单

java.security

数据库中的一个文档是这样的

let PollOptionSchema: mongoose.Schema = new Schema({
    name: String,
    voters: [{ user: { type: Schema.Types.ObjectId, ref: 'User' }, time: { type: Date, default: Date.now } }]
});

我想得到的是这个PollOption Documents只有id等于查询参数的用户。换句话说,如果$ userid =“56b0487a9f10c4e3d1012aff”,我想得到下面的文档。通常,“选民”中只有一个元素会返回。

{
    "_id": {
        "$oid": "56a8365fa619b9466d422ef7"
    },
    "name": "more",
    "voters": [
        {
            "user": {
                "$oid": "56a98ab1bc6279200c39c276"
            },
            "_id": {
                "$oid": "56a98ac0bc6279200c39c277"
            },
            "time": {
                "$date": "2016-01-28T03:28:00.090Z"
            }
        },
        {
            "user": {
                "$oid": "56b0487a9f10c4e3d1012aff"
            },
            "_id": {
                "$oid": "56b04e0fd889825ad7932336"
            },
            "time": {
                "$date": "2016-02-02T06:34:55.254Z"
            }
        }
    ],
    "__v": 2
}

我已尝试过以下代码($ userId是客户端的参数)

{
    "_id": {
        "$oid": "56a8365fa619b9466d422ef7"
    },
    "name": "more",
    "voters": [
        {
            "user": {
                "$oid": "56b0487a9f10c4e3d1012aff"
            },
            "_id": {
                "$oid": "56b04e0fd889825ad7932336"
            },
            "time": {
                "$date": "2016-02-02T06:34:55.254Z"
            }
        }
    ],
    "__v": 2
}

但上面的查询只返回null。我已经在网上搜索了很长时间但找不到解决方案。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

您有三种方法可以解决此问题,所有这些方法都使用 aggregation framework 来返回所需的结果。使用 aggregate() 方法,您可以使用 $filter 运算符返回voters数组,其中只包含与过滤条件匹配的元素,这适用于MongoDB 3.2版。那你怎么样呢? 嗯,以下示例演示了这一点:

// Define the pipeline
var pipeline = [
    {
        "$match": { "voters.user": userId }
    },
    {
        "$project": {
            "name": 1,
            // Use the $filter on the voters array
            "voters": {
                "$filter": {
                    "input": "$voters",
                    "as": "el",
                    "cond": {
                        "$eq": [ "$$el.user", userid  ]
                    }
                }
            }
        }
    }
];

// Run the aggregation pipeline
optionModel.aggregate(pipeline, function (err, result){
    if(err) { /* Handle error */ }
    console.log(result);
});

或者使用 aggregate() 方法上的流畅API运行聚合:

optionModel.aggregate()
          .match({ "$match": { "voters.user": userId } })
          .project({
               "name": 1,
               // Use the $filter on the voters array
               "voters": {
                  "$filter": {
                    "input": "$voters",
                    "as": "el",
                    "cond": {
                        "$eq": [ "$$el.user", userid  ]
                    }
               }
            }
         })
         .exec(function (err, result){
             if(err) { /* Handle error */ }
             console.log(result);
         });

对于MongoDB版本< 3.2,其他替代方法是使用 $map $setDifference 的组合来过滤数组中的内容,如下所示:

// Define the pipeline
var pipeline = [
    {
        "$match": { "voters.user": userId }
    },
    {
        "$project": {
            "name": 1,
            // Use $map and $setDifference on the voters array
            "votes": { 
                "$setDifference": [
                    { 
                        "$map": {
                            "input": "$votes",
                            "as": "el",
                            "in": { 
                                "$cond": [
                                    { "$eq": [ "$$el.user", userId ] },
                                    "$$el",
                                    false
                                ]
                            }
                        }
                    },
                    [false]
                ]
            }
        }
    }
];

或者较弱的高性能查询 $unwind

// Define the pipeline
var pipeline = [
    {
        "$match": { "votes.user": userId }
    },
    { "$unwind": "$votes" },
    {
        "$match": { "votes.user": userId }
    },
    {
        "$group": {
            "_id": "$_id",
            "votes": { "$push": "$votes" },
            "name": { "$first": "$name" }
        }
    }
];