$redact (aggregation)

Definition

  • $redact

New in version 2.6.

Restricts the contents of the documents based on information storedin the documents themselves.

Diagram of security architecture with middleware and redaction.

The $redact stage has the following prototype form:

  1. { $redact: <expression> }

The argument can be any valid expression as long as it resolves to $$DESCEND,$$PRUNE, or $$KEEP system variables. For more information onexpressions, see Expressions.

System VariableDescription$$DESCEND$redact returns the fields at the current document level,excluding embedded documents. To include embedded documents andembedded documents within arrays, apply the $condexpression to the embedded documents to determine access for theseembedded documents.$$PRUNE$redact excludes all fields at this currentdocument/embedded document level, without further inspection ofany of the excluded fields. This applies even if the excludedfield contains embedded documents that may have different accesslevels.$$KEEP$redact returns or keeps all fields at thiscurrent document/embedded document level, without furtherinspection of the fields at this level. This applies even ifthe included field contains embedded documents that may havedifferent access levels.

Examples

The examples in this section use thedb.collection.aggregate() helper provided in the 2.6 versionof the mongo shell.

Evaluate Access at Every Document Level

A forecasts collection contains documents of the following formwhere the tags field lists the different access values for thatdocument/embedded document level; i.e. a value of [ "G", "STLW" ]specifies either "G" or "STLW" can access the data:

  1. {
  2. _id: 1,
  3. title: "123 Department Report",
  4. tags: [ "G", "STLW" ],
  5. year: 2014,
  6. subsections: [
  7. {
  8. subtitle: "Section 1: Overview",
  9. tags: [ "SI", "G" ],
  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" ],
  20. content: {
  21. text: "Section 3: This is the content of section3.",
  22. tags: [ "HCS" ]
  23. }
  24. }
  25. ]
  26. }

A user has access to view information with either the tag "STLW" or"G". To run a query on all documents with year 2014 for thisuser, include a $redact stage as in the following:

  1. var userAccess = [ "STLW", "G" ];
  2. db.forecasts.aggregate(
  3. [
  4. { $match: { year: 2014 } },
  5. { $redact: {
  6. $cond: {
  7. if: { $gt: [ { $size: { $setIntersection: [ "$tags", userAccess ] } }, 0 ] },
  8. then: "$$DESCEND",
  9. else: "$$PRUNE"
  10. }
  11. }
  12. }
  13. ]
  14. );

The aggregation operation returns the following “redacted” document:

  1. {
  2. "_id" : 1,
  3. "title" : "123 Department Report",
  4. "tags" : [ "G", "STLW" ],
  5. "year" : 2014,
  6. "subsections" : [
  7. {
  8. "subtitle" : "Section 1: Overview",
  9. "tags" : [ "SI", "G" ],
  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. }

See also

$size, $setIntersection

Exclude All Fields at a Given Level

A collection accounts contains the following document:

  1. {
  2. _id: 1,
  3. level: 1,
  4. acct_id: "xyz123",
  5. cc: {
  6. level: 5,
  7. type: "yy",
  8. num: 000000000000,
  9. exp_date: ISODate("2015-11-01T00:00:00.000Z"),
  10. billing_addr: {
  11. level: 5,
  12. addr1: "123 ABC Street",
  13. city: "Some City"
  14. },
  15. shipping_addr: [
  16. {
  17. level: 3,
  18. addr1: "987 XYZ Ave",
  19. city: "Some City"
  20. },
  21. {
  22. level: 3,
  23. addr1: "PO Box 0123",
  24. city: "Some City"
  25. }
  26. ]
  27. },
  28. status: "A"
  29. }

In this example document, the level field determines the accesslevel required to view the data.

To run a query on all documents with status A and exclude _all_fields contained in a document/embedded document at level 5, include a$redact stage that specifies the system variable"$$PRUNE" in the then field:

  1. db.accounts.aggregate(
  2. [
  3. { $match: { status: "A" } },
  4. {
  5. $redact: {
  6. $cond: {
  7. if: { $eq: [ "$level", 5 ] },
  8. then: "$$PRUNE",
  9. else: "$$DESCEND"
  10. }
  11. }
  12. }
  13. ]
  14. );

The $redact stage evaluates the level field todetermine access. If the level field equals 5, then exclude allfields at that level, even if the excluded field contains embedded documentsthat may have different level values, such as the shipping_addrfield.

The aggregation operation returns the following “redacted” document:

  1. {
  2. "_id" : 1,
  3. "level" : 1,
  4. "acct_id" : "xyz123",
  5. "status" : "A"
  6. }

The result set shows that the $redact stage excludedthe field cc as a whole, including the shipping_addr fieldwhich contained embedded documents that had level field values equal to3 and not 5.

See also

Implement Field Level Redaction forsteps to set up multiple combinations of access for the same data.