Trying to use $redact to do cell level securty

All,

I am having similar using $redact example. I am trying to use $redact to do cell level security. Please let me know downside of using this feature to implement cell level security. Any help is greatly appreciated.

Here is example of document I tried to do

{
        "_id" : 1,
        "year" : 2013,
        "columns" : [
                {
                        "name" : "abc tag ",
                        "tags" : [
                                "PJ",
                                "MM"
                        ]
                },
                {
                        "ssn" : "12345666a",
                        "tags" : [
                                "KKLT"
                        ]
                },
                {
                        "placeofbirth" : "virginia",
                        "tags" : [
                                "FS"
                        ]
                }
        ]
}

{
        "_id" : 2,
        "year" : 2013,
        "columns" : [
                {
                        "name" : "abc tag  single",
                        "tags" : "PJ"
                },
                {
                        "ssn" : "12345666a",
                        "tags" : "KKLT"
                        
                },
                {
                        "placeofbirth" : "virginia",
                        "tags" :    "FS"
                        
                }
        ]
}

i want user to the field depending on the tags. I try to run the following query.

var userAccess = [ "KKLT", "FS" ];
db.book2.aggregate(
   [
     { $match: { year: 2013 } },
     { $redact: {
        $cond: {
           if: { $gt: [ { $size: { $setIntersection: [ "$tags", userAccess ] } }, 0 ] },
           then: "$$DESCEND",
           else: "$$PRUNE"
         }
       }
     }
   ]
);
Uncaught exception: Error: command failed: {

"ok" : 0,

"errmsg" : "The argument to $size must be an array, but was of type: null",

"code" : 17124,

"codeName" : "Location17124"

} : aggregate failed :

_getErrorWithCode@src/mongo/shell/utils.js:25:13

doassert@src/mongo/shell/assert.js:18:14

_assertCommandWorked@src/mongo/shell/assert.js:583:17

assert.commandWorked@src/mongo/shell/assert.js:673:16

DB.prototype._runAggregate@src/mongo/shell/db.js:266:5

DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1012:12

DBCollection.prototype.aggregate@:1:355

@(shell):1:1

Hi @Tony_Tran,

Welcome to MongoDB community

It looks like the $size was tried on a null expression.

You need to use a $cond and $ifNull to return an empty array if intersection yield null.

Thanks
Pavel

Thanks Pavel, can you give me an example on how? I tried different syntax but keep getting error. Sorry I am so new to this.

Did we ever get a sample of this? All of the documentation shows the use of redact when the field exists on ALL levels, meaning both the root and potential embedded documents, in an array or otherwise.

Using the example from documentation(https://www.mongodb.com/docs/manual/reference/operator/aggregation/redact/ with one added field at the embedded document level in the array), how would this work?

{
  _id: 1,
  title: "123 Department Report",
  tags: [ "G", "STLW" ],
  year: 2014,
  subsections: [
    {
      subtitle: "Section 1: Overview",
      tags: [ "SI", "G" ],
      content:  "Section 1: This is the content of section 1.",
      subsectionOnlyField: 1
    },
    {
      subtitle: "Section 2: Analysis",
      tags: [ "STLW" ],
      content: "Section 2: This is the content of section 2.",
      subsectionOnlyField: 2
    },
    {
      subtitle: "Section 3: Budgeting",
      tags: [ "TK" ],
      content: {
        text: "Section 3: This is the content of section 3.",
        tags: [ "HCS" ]
      },
      subsectionOnlyField: 1
    }
  ]
}

How would I redact only the array item with subsectionOnlyField = 2?

I have tried, with no success:

  • $subsections.subsectionOnlyField $EQ 2. This will indeed prune that one/keep all others depending on how you write it, but because the primary document does not even have the “subsectionOnlyField” it removes all data from the main document.

-I also tried adding an IFNULL set it to something for the “subsectionOnlyField”, that way on things like the root document where it does not exist, it would set it to something I WANT or allow, thus truly only pruning “bad” values.

This feels like it should be simple but I must be missing something.

Update and followup:

It seems like this works:

  { "$redact" : 
  	{
      "$cond": 
      {
         "if": 
         {  
           $or: 
           	[              
              {"$not": "$subsectionOnlyField"},
              {"$eq": [ "$subsectionOnlyField", SOMEVALUE ]}
          	] 
         },
         "then": "$$DESCEND",
         "else": "$$PRUNE"
    	}
		}
  }

However, is it possible to only execute the above redaction in one array?

using the data example from the previous post, if there were another array “subsections2” with data which has the same field name “subsectionOnlyField”, can I tell redaction to only redact in the Subsections array and not Subsections2 array?