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.
