Home > Software engineering >  Mongoid query records that have all their embedded documents matching a criteria
Mongoid query records that have all their embedded documents matching a criteria

Time:10-21

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.

  • Related