1

I have the following scheme; its a conversation scheme with as subdocument structure a username and enabled or disabled state;

conversation = {title: "title", 
users: [{"name: "a", "enabled": true}, {"name: "b", "enabled": false}]}

I want to select all the users that have an enabled state set to true. I found that $elemMatch in projection does just that, but only returns the first element... Putting $elemMatch in the query parts does not do anything...

Any help is appreciated

Community
  • 1
  • 1
Pieterjan
  • 445
  • 6
  • 23

1 Answers1

1

Assuming that the mongo structure is as follows

> db.conversation.find().pretty()
{
    "_id" : ObjectId("55337db16f20d74ec08c33b1"),
    "title" : "title",
    "users" : [
        {
            "name" : "a",
            "enabled" : true
        },
        {
            "name" : "b",
            "enabled" : false
        }
    ]
}
{
    "_id" : ObjectId("553380ac6f20d74ec08c33b2"),
    "users" : [
        {
            "name" : "a",
            "enabled" : false
        },
        {
            "name" : "b",
            "enabled" : false
        }
    ],
    "title" : "Abc"
}

If you wish to return those entries that have users with "enabled" field set to "true", then following would do

> db.conversation.find({users: {$elemMatch: { "name":{$exists: true} ,"enabled":true}  }}).pretty()
{
    "_id" : ObjectId("55337db16f20d74ec08c33b1"),
    "title" : "title",
    "users" : [
        {
            "name" : "a",
            "enabled" : true
        },
        {
            "name" : "b",
            "enabled" : false
        }
    ]
}

But I don't like the data structure you are using.

Let's say (assuming that would be case) you have to keep track of a conversation. Will the following work for you?

conversation = {title: "title", users: ["a", "b"]}

Assuming in your case that "a","b" are unique identifications, otherwise I'd recommend you keep the IDs here.

conversation = {title: "title", users: [3434, 984]}

Have another collection that stores your users data(following would be typical entry).

{"user_id": 3434, "enabled": true}
...

In this case, you can run an aggregation or something, selecting user list from conversations collection to return you the unique list of all users. You can then query that list in your users collection to see which are actually enabled/disabled.

Now, assuming I am wrong and this enabled disabled is actually indicating which user is enabled/disabled in a particular conversation. Then I'd say your structure should be.

conversation = {title: "title", users: [232, 3453], disabled: [232]}

Hope this helps!

Syed Mauze Rehan
  • 1,125
  • 14
  • 31
  • Thank you for the very long answer. If I do use your last suggestion, as in keeping an array of disabled users (no pun intended), how would I go about selecting and displaying only the enabled users in this particular conversation? – Pieterjan Apr 19 '15 at 11:41
  • In that case I'd say when marking a user disabled from a conversation, you remove that from users list and move that to the disabled list. That way you can be sure that only enabled ones exist in 'users' field, where as the disabled ones exist in the 'disabled' field. Otherwise, if you want to keeping all users in the 'users' field and keep a separate list for maintaining the disabled list then code would do it. Or you can use a mongo pipeline to return to you a custom entry for each entry in the collection (doing the exact same thing as code would do, users minus disabled = enabled users) – Syed Mauze Rehan Apr 19 '15 at 12:49
  • Please refer to this; http://docs.mongodb.org/manual/reference/operator/aggregation/setIntersection/ – Syed Mauze Rehan Apr 19 '15 at 12:52
  • Refer to the second for this question if you are using mongodb version < 2.6 http://stackoverflow.com/questions/17268770/how-to-use-mongodb-aggregation-for-general-purpose-set-operations-union-inters – Syed Mauze Rehan Apr 19 '15 at 12:56