Reputation: 2783
I have a collection called elections and in the elections schema there's a nested array called votes. I'm trying to query an election by id as well as filter the nested votes objects by a userId
property. I want the parent election object to always be returned and if the current user hasn't voted in the election the votes
property should be an empty array.
This is my query:
Election.findOne({
_id: electionId,
'votes.userId': userId
})
.exec()
The issue is that if there aren't any votes with the userId
the parent Election object isn't returned as well. Is there any way to filter the votes
property but also make it not-required for matching the parent election object.
I come from a background in sql and in the Sequelize here is how I'd do what I want to do:
models.Election.findOne({
where: {
id: electionId
}
include: {
model: models.Vote,
where: {
userId
},
required: false
}
})
Upvotes: 1
Views: 1403
Reputation: 74831
MongoDB has a $filter
aggregation
const res = await Election.aggregate([
{ $match: { _id: mongoose.Types.ObjectId(electionId) } },
{ $project: {
_id: 1,
votes: { $filter: {
input: '$votes',
as: 'userVote',
cond: { $eq: [ '$$userVote', userId ] },
}}
}}
])
Which equates to a plain js filter like
votes.filter(userVote => userVote.userId === userId)
Some other answers to this question on filtering arrays in mongodb are relevant too but the query requirement there is slightly different to your question, more like your initial attempt.
Upvotes: 3