Question

I've updated to Mongodb 2.6.1 and have attempted, unsuccessfully, to use the new $redact aggregation function to solve a business problem. All the $redact examples I've come across evaluate against an external variable or static value.

I need to eliminate some resulting documents based on a value in a sibling subdocument. I believe $redact would be the way to do this, if possible, but like all technical challenges I'm sure there are several ways to resolve. I want to keep the document structure as is. I can eliminate the extra results in my application code, if needed, but would prefer the data come out of the database just right.

Here's what I'm trying to do...

The collection

Location.id is an int set in the application code and is only used to create a relationship between locations and rewards (a reward may only be valid at a few locations). The below doc has been pared down to focus on what important here.

{
    "_id" : ObjectId("53728b24e4749ce8ac3f31e7"),
    "name" : "Business name",
    "locations" : [ 
        {
            "name" : "Downtown Norfolk",
            "id" : 3
        }, 
        {
            "name" : "McDonald's Suffolk",
            "id" : 4
        }
    ],
    "rewards" : [ 
        {
            "name" : "Reward for Downtown Norfolk Only",
            "locationIDs" : [3]
        }
    ]
}

The query

What I need to produce is a list of each reward and its applicable locations. I can use the below to get the full list of location/rewards...

collection.aggregate([
  { $unwind: '$rewards' },
  { $unwind:  '$locations' },                      
  { $project: { name: 1, rewards: 1, locations: 1 } }
  }    
])

The query results

The below basically joins all locations to all rewards. But this reward only applies to location.id = 3, not to 3 and 4, so I need to eliminate location.id = 4 from the results. I need to continue to use aggregation because the actual query (not shown here) includes $geoNear.

{
    "result" : [ 
        {
            "_id" : ObjectId("53728b24e4749ce8ac3f31e7"),
            "name" : "Business name",
            "locations" : {
                "name" : "Downtown Norfolk",
                "id" : 3
            },
            "rewards" : {
                "name" : "Newport News Only Reward",
                "locationIDs" : [3]
            }
        }, 
        {
            "_id" : ObjectId("53728b24e4749ce8ac3f31e7"),
            "name" : "Business name",
            "locations" : {
                "name" : "McDonald's Suffolk",
                "id" : 4
            },
            "rewards" : {
                "locationIDs" : [3]
            }
        }
    ],
    "ok" : 1
}

The query results I want

What I'm trying to do is eliminate the last document from the above query results, where the locationIDs don't match (where locations.id = 4 is not in rewards.locationIDs = [3]). Below is what I would like to get back from Mongo.

{
    "result" : [ 
        {
            "_id" : ObjectId("53728b24e4749ce8ac3f31e7"),
            "name" : "Business name",
            "locations" : {
                "name" : "Downtown Norfolk",
                "id" : 3
            },
            "rewards" : {
                "name" : "Newport News Only Reward",
                "locationIDs" : [ 
                    3
                ]
            }
        }
    ],
    "ok" : 1
}

Much appreciated.

Was it helpful?

Solution

Not sure $redact would help. I suggest to use $cmp operator to compare values, like this:

db.ttt.aggregate({$unwind:"$locations"},
                 {$unwind:"$rewards"},
                 {$unwind:"$rewards.locationIDs"},
                 {$project:
                          {_id:1,
                           name:1,
                           locations:1,
                           rewards:1,
                           equality:{
                                     $cmp:['$locations.id','$rewards.locationIDs']
                                    }
                          }
                 },
                 {$match:{equality:0}})

It will exclude not matched documents, and then you need to group back

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top