Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redact in mongodb seems obscure to me

I'm fighting with redact right now and I'm not sure to understand it.

I just read the docs and tried to use redact on a collection grades (it comes from mongodb online training)

A document in the collection "grades" looks like this :

{
    "_id" : ObjectId("50b59cd75bed76f46522c34e"),
    "student_id" : 0,
    "class_id" : 2,
    "scores" : [ 
        {
            "type" : "exam",
            "score" : 57.92947112575566
        }, 
        {
            "type" : "quiz",
            "score" : 21.24542588206755
        }, 
        {
            "type" : "homework",
            "score" : 68.19567810587429
        }, 
        {
            "type" : "homework",
            "score" : 67.95019716560351
        }, 
        {
            "type" : "homework",
            "score" : 18.81037253352722
        }
    ]
}

I use the following query :

db.grades.aggregate([
    { $match: { student_id: 0 } },
    { 
        $redact: {
            $cond: {
                if: { $eq: [ "$type" , "exam" ] },
                then: "$$PRUNE",
                else: "$$DESCEND"
            }
        }
    }

] );

With this query, each type an exam is found, this sub document should be excluded. And it works, the result is:

{
    "_id" : ObjectId("50b59cd75bed76f46522c34e"),
    "student_id" : 0,
    "class_id" : 2,
    "scores" : [ 
    {
        "type" : "quiz",
        "score" : 21.24542588206755
    }, 
    {
        "type" : "homework",
        "score" : 68.19567810587429
    }, 
    {
        "type" : "homework",
        "score" : 67.95019716560351
    }, 
    {
        "type" : "homework",
        "score" : 18.81037253352722
    }
]
}

but if I invert the condition, I expect that only exams are kept in the result :

if: { $eq: [ "$type" , "exam" ] },
       then: "$$DESCEND",
       else: "$$PRUNE" 

however the result is empty.

I don't understand why subdocument of type "exam" are not included.

like image 988
Hugo Lassiège Avatar asked Sep 18 '15 13:09

Hugo Lassiège


People also ask

What is redact in MongoDB?

$redact. Restricts the contents of the documents based on information stored in the documents themselves.

Is MongoDB aggregate slow?

On large collections of millions of documents, MongoDB's aggregation was shown to be much worse than Elasticsearch. Performance worsens with collection size when MongoDB starts using the disk due to limited system RAM. The $lookup stage used without indexes can be very slow.


1 Answers

The $redact stage starts at the root document and its fields, and only when that document fulfills the condition to $$DESCEND, it examines the sub-documents included in that document. That means the first thing $redact does with your document is examine this:

{
    "_id" : ObjectId("50b59cd75bed76f46522c34e"),
    "student_id" : 0,
    "class_id" : 2,
    "scores" : [] // Some array. I will look at this later.
}

It doesn't even find a type field here, so $eq: [ "$type" , "exam" ] is false. What did you tell $redact to do when the condition is false? else: "$$PRUNE", so the whole document is pruned before the sub-documents are examined.

As a workaround, test if $type is either "exam" or doesn't exist. You didn't explicitly ask for a working solution, so I will leave it as an exercise to you to figure out how to do this.

like image 65
Philipp Avatar answered Nov 16 '22 00:11

Philipp