4
db.chat.find().pretty().limit(3)
{
    "_id" : ObjectId("593921425ccc8150f35e7662"),
    "user1" : 1,
    "user2" : 2,
    "messages" : [
        {
            "capty" : 'A',
            "body" : "hiii 0"
        },
        {
            "capty" : 'B',
            "body" : "hiii 1"
        },
        {
            "capty" : 'A',
            "body" : "hiii 2"
        }
    ]
}
{
    "_id" : ObjectId("593921425ccc8150f35e7663"),
    "user1" : 1,
    "user2" : 3,
    "messages" : [
        {
            "capty" : 'A',
            "body" : "hiii 0"
        },
        {
            "capty" : 'A',
            "body" : "hiii 1"
        },
        {
            "capty" : 'B',
            "body" : "hiii 23"
        }
    ]
}
{
    "_id" : ObjectId("593921425ccc8150f35e7664"),
    "user1" : 1,
    "user2" : 4,
    "messages" : [
        {
            "capty" : 'A',
            "body" : "hiii 0"
        },
        {
            "capty" : 'B',
            "body" : "hiii 1"
        },
        {
            "capty" : 'B',
            "body" : "hiii 24"
        }
    ]
}

Query needed: Row count where "user1" : 1, "capty" : 'B' and "body" : "hiii 1"

I tried:

db.chat.aggregate([
 { "$match": { "user1": 1,  "messages.capty": "B" , "messages.body": "hiii 1" } }
])

but this is not working as matches any messages where capty = 'B' or "messages.body": "hiii 1".

i.e desireable output. 2 (for record1 and record3)

6
  • db.chat.findOne({"user":1, "message.capty": "B", "message.body" : "hiii 1"})Ought to work. Why are you aggregating if you are not referencing ? Commented Jun 22, 2017 at 10:26
  • @Ozan No it won't the conditions would be considered against "all" array elements without $elemMatch, which specifically looks on the current array element for both. Commented Jun 22, 2017 at 10:33
  • @NeilLunn In that case my example would return any document that matches has one of the given specifications, wouldn't it ? Commented Jun 22, 2017 at 10:36
  • @Ozan Read the answer and try it! Commented Jun 22, 2017 at 10:36
  • @NeilLunn I created the same db and used the methods and checked them out! You were right! My method doesn't match anything. Commented Jun 22, 2017 at 11:03

1 Answer 1

4

You need $elemMatch here. That operator is used for "multiple criteria" from within an array element:

db.chat.find({
 "user1": 1, 
 "messages": { 
   "$elemMatch": { "capty": "B" , "body": "hiii 1" }
 }
})

And the count:

db.chat.find({
 "user1": 1, 
 "messages": { 
   "$elemMatch": { "capty": "B" , "body": "hiii 1" }
 }
}).count()

That will match the correct documents and return their count.

Actual documents returned:

{
        "_id" : ObjectId("593921425ccc8150f35e7662"),
        "user1" : 1,
        "user2" : 2,
        "messages" : [
                {
                        "capty" : "A",
                        "body" : "hiii 0"
                },
                {
                        "capty" : "B",
                        "body" : "hiii 1"
                },
                {
                        "capty" : "A",
                        "body" : "hiii 2"
                }
        ]
}
{
        "_id" : ObjectId("593921425ccc8150f35e7664"),
        "user1" : 1,
        "user2" : 4,
        "messages" : [
                {
                        "capty" : "A",
                        "body" : "hiii 0"
                },
                {
                        "capty" : "B",
                        "body" : "hiii 1"
                },
                {
                        "capty" : "B",
                        "body" : "hiii 24"
                }
        ]
}

The same "query" condition applies to aggregate $match if you really want to use it there. But for a "count", it's faster to use the "cursor".

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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