问题
I have seen kind of a similar question, but it has no answer so it doesn't answer my question.
How to group arrays based on another array in mongodb aggregation?
Assume you have these schemas:
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
},
});
How can I, in mongodb aggregation, sort the castedVotes in arrays based on their choice. For example consider the data sample below:
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},
]
NOTE: There are no votes casted in choiceC
I am trying to create an aggregation query that returns an array based on each choice. For example (see below).
//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
}
How to group the CastedVote
array based Poll.arrayOfNamesOfChoices
array in mongodb aggregation?
回答1:
How to group the CastedVote array based Poll.arrayOfNamesOfChoices array in mongodb aggregation?
If you have a collection called poll
, containing a document as below
{ "_id": 100,
"choices": [
{ "name": "choiceA", "id": 0 },
{ "name": "choiceB", "id": 1 },
{ "name": "choiceC", "id": 2 } ]
}
And another collection called castedvote
, containing documents as below:
{"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("...")}
You can perform aggregation below:
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"}},
]);
Using $arrayToObject to create a dynamic field name from the field values. The output would be:
{ "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": [ ] }
来源:https://stackoverflow.com/questions/60740127/how-to-group-arrays-based-on-another-array-in-mongodb-aggregation