Как сгруппировать массивы на основе другого массива в агрегации mongodb? - PullRequest
0 голосов
/ 18 марта 2020

Я видел подобный вопрос , но у него нет ответа, поэтому он не отвечает на мой вопрос.

Как сгруппировать массивы на основе другого массива в агрегации 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 отсортировать castedVotes в массивы на основе их выбора. Например, рассмотрим образец данных ниже:

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
}

Как сгруппировать массив Poll.arrayOfNamesOfChoices на основе массива *1027* в агрегацию mongodb?

1 Ответ

1 голос
/ 20 марта 2020

Как сгруппировать массив Polted.arrayOfNamesOfChoices на основе массива CastedVote в агрегации mongodb?

Если у вас есть коллекция с именем 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 создать динамическое c имя поля из значений поля. Вывод будет:

{  "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": [ ] }
...