1

I have multiple data something like this

{
    "_id" : ObjectId("57189fcd72b6e0480ed7a0a9"),
    "venueId" : ObjectId("56ce9ead08daba400d14edc9"),
    "companyId" : ObjectId("56e7d62ecc0b8fc812b2aac5"),
    "cardTypeId" : ObjectId("56cea8acd82cd11004ee67a9"),
    "matchData" : [ 
        {
            "matchId" : ObjectId("57175c25561d87001e666d12"),
            "matchDate" : ISODate("2016-04-08T18:30:00.000Z"),
            "matchTime" : "20:00:00",
            "_id" : ObjectId("57189fcd72b6e0480ed7a0ab"),
            "active" : 3,
            "cancelled" : 0,
            "produced" : 3
        }, 
        {
            "matchId" : ObjectId("57175c25561d87001e666d13"),
            "matchDate" : ISODate("2016-04-09T18:30:00.000Z"),
            "matchTime" : "20:00:00",
            "_id" : ObjectId("57189fcd72b6e0480ed7a0aa"),
            "active" : null,
            "cancelled" : null,
            "produced" : null
        }
    ],
    "__v" : 0
}

i m doing group by companyId and its work fine But i want to search in matchData based on matchtime and matchId For that purpose i am $unwind matchData after unwind i using my search query like this

db.getCollection('matchWiseData').aggregate([
{"$match":{
   "matchData.matchId":{"$in":[ObjectId("57175c25561d87001e666d12")]}
}},
{"$unwind":"$matchData"},
{"$match":{
    "matchData.matchId":{"$in":[ObjectId("57175c25561d87001e666d12")]}}
}])

its give me proper result but after applying unwind is there any way to undo it I m using unwind to just search inside subdocument or there is any other way to search inside subdocument.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
Dexter
  • 1,804
  • 4
  • 24
  • 53

1 Answers1

9

Well you can of course just use $push and $first in a $group to get the document back to what it was:

db.getCollection('matchWiseData').aggregate([
    { "$match":{
       "matchData.matchId":{"$in":[ObjectId("57175c25561d87001e666d12")]}
    }},
    { "$unwind":"$matchData"},
    { "$match":{
        "matchData.matchId":{"$in":[ObjectId("57175c25561d87001e666d12")]}
    }},
    { "$group": {
        "_id": "$_id",
        "venueId": { "$first": "$venueId" },
        "companyId": { "$first": "$companyId" },
        "cardTypeId": { "$first": "$cardTypeId" },
        "matchData": { "$push": "$matchData" }
    }}
])

But you probably should have just used $filter with MongoDB 3.2 in the first place:

db.getCollection('matchWiseData').aggregate([
    { "$match":{
       "matchData.matchId":{"$in":[ObjectId("57175c25561d87001e666d12")]}
    }},
    { "$project": {
        "venueId": 1,
        "companyId": 1,
        "cardTypeId": 1,
        "matchData": { 
            "$filter": {
                "input": "$matchData",
                "as": "match",
                "cond": {
                   "$or": [
                       { "$eq": [ "$$match.matchId", ObjectId("57175c25561d87001e666d12") ] }
                   ]
                }
            }
        }
    }}
])

And if you had at least MongoDB 2.6, you still could have used $map and $setDifference instead:

db.getCollection('matchWiseData').aggregate([
    { "$match":{
       "matchData.matchId":{"$in":[ObjectId("57175c25561d87001e666d12")]}
    }},
    { "$project": {
        "venueId": 1,
        "companyId": 1,
        "cardTypeId": 1,
        "matchData": { 
            "$setDifference": [
                { "$map": {
                    "input": "$matchData",
                    "as": "match",
                    "in": {
                        "$cond": [
                           { "$or": [
                              { "$eq": [ "$$match.matchId", ObjectId("57175c25561d87001e666d12") ] }
                           ]},
                            "$$match",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }}
])

That's perfectly fine when every array element already has a "unique" identifier, so the "set" operation just removes the false values from $map.

Both of those a ways to "filter" content from an array without actually using $unwind


N.B: Not sure if you really grasp that $in is used to match a "list of conditions" rather than being required to match on arrays. So generally the condition can just be:

 "matchData.matchId": ObjectId("57175c25561d87001e666d12")

Where you only actually have a single value to match on. You use $in and $or when you have a "list" of conditions. Arrays themselves make no difference to the operator required.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317