Implement Field Level Redaction

The $redact pipeline operator restricts the contents of thedocuments based on information stored in the documents themselves.

Diagram of security architecture with middleware and redaction.

To store the access criteria data, add a field to the documents andembedded documents. To allow for multiple combinations of access levels forthe same data, consider setting the access field to an array of arrays.Each array element contains a required set that allows a user with thatset to access the data.

Then, include the $redact stage in thedb.collection.aggregate() operation to restrict contents ofthe result set based on the access required to view the data.

For more information on the $redact pipeline operator,including its syntax and associated system variables as well asadditional examples, see $redact.

Procedure

For example, a forecasts collection contains documents of thefollowing form where the tags field determines the access levelsrequired to view the data:

  1. {
  2. _id: 1,
  3. title: "123 Department Report",
  4. tags: [ [ "G" ], [ "FDW" ] ],
  5. year: 2014,
  6. subsections: [
  7. {
  8. subtitle: "Section 1: Overview",
  9. tags: [ [ "SI", "G" ], [ "FDW" ] ],
  10. content: "Section 1: This is the content of section 1."
  11. },
  12. {
  13. subtitle: "Section 2: Analysis",
  14. tags: [ [ "STLW" ] ],
  15. content: "Section 2: This is the content of section 2."
  16. },
  17. {
  18. subtitle: "Section 3: Budgeting",
  19. tags: [ [ "TK" ], [ "FDW", "TGE" ] ],
  20. content: {
  21. text: "Section 3: This is the content of section3.",
  22. tags: [ [ "HCS"], [ "FDW", "TGE", "BX" ] ]
  23. }
  24. }
  25. ]
  26. }

For each document, the tags field contains various access groupingsnecessary to view the data. For example, the value [ [ "G" ], ["FDW", "TGE" ] ] can specify that a user requires either access level["G"] or both [ "FDW", "TGE" ] to view the data.

Consider a user who only has access to view information tagged witheither "FDW" or "TGE". To run a query on all documents withyear 2014 for this user, include a $redact stage as inthe following:

  1. var userAccess = [ "FDW", "TGE" ];
  2. db.forecasts.aggregate(
  3. [
  4. { $match: { year: 2014 } },
  5. { $redact:
  6. {
  7. $cond: {
  8. if: { $anyElementTrue:
  9. {
  10. $map: {
  11. input: "$tags" ,
  12. as: "fieldTag",
  13. in: { $setIsSubset: [ "$$fieldTag", userAccess ] }
  14. }
  15. }
  16. },
  17. then: "$$DESCEND",
  18. else: "$$PRUNE"
  19. }
  20. }
  21. }
  22. ]
  23. )

The aggregation operation returns the following “redacted” document for the user:

  1. { "_id" : 1,
  2. "title" : "123 Department Report",
  3. "tags" : [ [ "G" ], [ "FDW" ] ],
  4. "year" : 2014,
  5. "subsections" :
  6. [
  7. {
  8. "subtitle" : "Section 1: Overview",
  9. "tags" : [ [ "SI", "G" ], [ "FDW" ] ],
  10. "content" : "Section 1: This is the content of section 1."
  11. },
  12. {
  13. "subtitle" : "Section 3: Budgeting",
  14. "tags" : [ [ "TK" ], [ "FDW", "TGE" ] ]
  15. }
  16. ]
  17. }

See also

$map, $setIsSubset,$anyElementTrue