0

I have a collection Project with documents that look like the following :

{
  _id: ObjectId(...),
  name: "some name",
  members: [
    {
      user: ObjectId(...),
      joined: false,
      ...
    },
    {
      user: ObjectId(...),
      joined: true,
      ...
    },
    {
      user: ObjectId(...),
      joined: true,
      ...
    },
    ...
  ]

Given two user ids, I would like to query all the documents where members contains at least both users with joined equal to true. Additional members could be present, but the two must be present. I have no clue what to do, especially with $elemMatch. Any idea ?

Intuitively, I would have done something like this :

Project.find({
  members: {
    $elemMatch: [
      {
        user: firstId,
        joined: true
      },
      {
        user: secondId,
        joined: true
      }
    ]
  }
})

3 Answers 3

1

Use $and over two $elemMatch clauses:

MongoDB Enterprise mongos> db.foo.insert({_id:1,members:[{a:1,joined:true},{a:2,joined:true}]})
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise mongos> db.foo.insert({_id:2,members:[{a:1,joined:true},{a:2,joined:false}]})
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise mongos> db.foo.find({$and:[{members:{$elemMatch:{a:1,joined:true}}},{members:{$elemMatch:{a:2,joined:true}}}]})
{ "_id" : 1, "members" : [ { "a" : 1, "joined" : true }, { "a" : 2, "joined" : true } ] }
Sign up to request clarification or add additional context in comments.

Comments

1

You can achieve this using aggregation.

db.collection.aggregate([{
    
    $addFields:{
        members:{
            $filter:{
                input:"$members",
                cond:{
                    $or:[
                        {
                            $and:[
                                {$eq:["$$this.user",ObjectId("5f49d0623c7e81bfcf37b8ed")]},
                                {$eq:["$$this.joined",true]}
                                ]
                        }
                        ,
                        {
                            $and:[
                                {$eq:["$$this.user",ObjectId("5f49d075d14cb1f5e2ff6a77")]},
                                {$eq:["$$this.joined",true]}
                                ]
                        }
                        ]
                }
            }
        }
    }
}])

Working Mongo playground

1 Comment

Yep, that's what I wanted to avoid. Any alternative without aggregation ?
1

You can do:

db.collection.find({
  "members.joined": true,
  "members.user": {
    $all: [
      3,
      4
    ]
  }
})

Playground

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.