Let's say I have models like this
class Band
include Mongoid::Document
embeds_many :albums
end
class Album
include Mongoid::Document
field :name, type: String
field :producer, type: String
embedded_in :band
end
What I want to get is all bands that have all their albums produced by "George Martin".
I tried Band.where('albums.producer' => 'George Martin')
but it's matching all bands which have at least once George Martin in their producers.
Examples:
This band should match (because all their albums have been produced by George Martin):
{
"_id" : ObjectId("blabla"),
"albums" : [
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e0"),
"name" : "Violator",
"producer" : "George Martin"
}
]
}
This band shouldn't match (because the album " " has been produced by another producer):
{
"_id" : ObjectId("blablabla"),
"albums" : [
{
"_id" : ObjectId("album1"),
"name" : "/",
"producer" : "George Martin"
},
{
"_id" : ObjectId("album2"),
"name" : " ",
"producer" : "Another producer"
}
]
}
CodePudding user response:
You can use $reduce to process your albums
array. By setting an initial value of true
, you can conditionally set the value to false
when one entry is not equal to
"George Martin" by using $and
condition with the accumulator. $match
the final result of the accumulator to perform the filtering.
{
"$reduce": {
"input": "$albums",
"initialValue": true,
"in": {
$and: [
"$$value",
{
$eq: [
"$$this.producer",
"George Martin"
]
}
]
}
}
}
Here is the Mongo playground for your reference.