如何在mongodb聚合中基于另一个数组对数组进行分组?

时间:2020-03-18 12:59:27

标签: mongodb mongodb-query aggregation-framework

我见过kind of a similar question,但是它没有答案,因此无法回答我的问题。

如何在mongodb聚合中基于另一个数组对数组进行分组?

假设您具有以下架构:

PollSchema

const PollSchema = new mongoose.Schema({
    numberOfChoices: {
        type: Number,
        required: true,
        min: [1, "Number of choices must be at least 1"],
        max: [10, "Number of choices cannot be more than 10"],
    },
    arrayOfNamesOfChoices:[{
        name: {
            type: String,
            required: true,
        },
    }],
});

CastedVotedSchema

const CastedVoteSchema = new mongoose.Schema({
    voter: {
        type: String,
        required: true,
    },
    choice: {
        type: Number,
        required: true,
        min:0,
        max:9
    },
});

在mongodb聚合中,我如何根据选择的数组对castedVote进行排序。例如,考虑以下数据示例:

Poll = {
    numberOfChoices: 3
    arrayOfNamesOfChoices: [
        {name:'choiceA'},{name:'choiceB'},{name:'choiceC'}
    ]
}

CastedVotes = [
    {voter: 'Juzi', choice: 0},{voter: 'Juma', choice: 0},{voter: 'Jane', choice: 0},
    {voter: 'Jamo', choice: 1},{voter: 'Juju', choice: 1},{voter: 'Jana', choice: 1},
]

注意choiceC中没有投票

我正在尝试创建一个聚合查询,该查询将根据每个选择返回一个数组。例如(见下文)。

//below is the result I desire to have 
{ 
    totalVotes:[
        {voter: 'Juzi', choice: 0},{voter: 'Juma', choice: 0},{voter: 'Jane', choice: 0},
        {voter: 'Jamo', choice: 1},{voter: 'Juju', choice: 1},{voter: 'Jana', choice: 1},
    ], 
    choiceA:[{voter: 'Juzi', choice: 0},{voter: 'Juma', choice: 0},{voter: 'Jane', choice: 0}],
    choiceB:[{voter: 'Jamo', choice: 1},{voter: 'Juju', choice: 1},{voter: 'Jana', choice: 1}],
    choiceC:[],// the choiceC array should be present and empty
}

如何在mongodb聚合中将基于CastedVote的{​​{1}}数组分组?

1 个答案:

答案 0 :(得分:1)

如何在mongodb聚合中将基于CastedVote数组的Poll.arrayOfNamesOfChoices数组分组?

如果您有一个名为poll的集合,其中包含如下文档

{ "_id": 100,
  "choices": [
    { "name": "choiceA", "id": 0 },
    { "name": "choiceB", "id": 1 },
    { "name": "choiceC", "id": 2 } ]
}

另一个名为castedvote的集合,其中包含以下文档:

{"voter": "Juzi", "choice": 0, "pollId": ObjectId("...")}
{"voter": "Juma", "choice": 0, "pollId": ObjectId("...")}
{"voter": "Jane", "choice": 0, "pollId": ObjectId("...")}
{"voter": "Jamo", "choice": 1, "pollId": ObjectId("...")}
{"voter": "Juju", "choice": 1, "pollId": ObjectId("...")}
{"voter": "Jana", "choice": 1, "pollId": ObjectId("...")}

您可以在下面执行聚合:

db.poll.aggregate([
    {"$match": {"_id": 100}}, 
    {"$unwind":"$choices"},
    {"$lookup": {
        "from":"castedvotes", 
        "let": {"c":"$choices"}, 
        "pipeline":[
            {"$match":
                {"$expr":
                    {"$eq": ["$choice", "$$c.id"]},
            }},
        ], 
        "as":"voters"
    }},
    {"$addFields":{
        "x": {
            "$arrayToObject": [ [{"k": "$choices.name", "v": "$voters"}] ]
        }
    }}, 
    {"$replaceRoot": {"newRoot": "$x"}}, 
]);    

使用$arrayToObject根据字段值创建动态字段名。输出为:

{  "choiceA": [
        {"_id": ObjectId("..."), "voter": "Juzi", "choice": 0, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Juma", "choice": 0, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Jane", "choice": 0, "pollId": 100 },
]},
{  "choiceB": [
        {"_id": ObjectId("..."), "voter": "Jamo", "choice": 1, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Juju", "choice": 1, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Jana", "choice": 1, "pollId": 100 }
]},
{  "choiceC": [ ] }