// Check $redact pipeline stage. load('jstests/aggregation/extras/utils.js'); t = db.jstests_aggregation_redact; t.drop(); // this document will always be present but its content will change t.save({ _id: 1, level: 1, // b will present on level 3, 4, and 5 b: { level: 3, c: 5, // always included when b is included // the contents of d test that if we cannot see a document then we cannot see its // array-nested subdocument even if we have permissions to see the subdocument. // it also tests arrays containing documents we cannot see d: [ {level: 1, e: 4}, {f: 6}, {level: 5, g: 9}, "NOT AN OBJECT!!11!", // always included when b is included [2, 3, 4, {level: 1, r: 11}, {level: 5, s: 99}] // nested array should always be included once b is // but the second object should only show up at level 5 ] }, // the contents of h test that in order to see a subdocument (j) we must be able to see all // parent documents (h and i) even if we have permissions to see the subdocument h: {level: 2, i: {level: 4, j: {level: 1, k: 8}}}, // l checks that we get an empty document when we can see a document but none of its fields l: {m: {level: 3, n: 12}}, // o checks that we get an empty array when we can see a array but none of its entries o: [{level: 5, p: 19}], // q is a basic field check and should always be included q: 14 }); // this document will sometimes be missing t.save({ _id: 2, level: 4, }); a1 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 1]}, "$$DESCEND", "$$PRUNE"]}}); a2 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 2]}, "$$DESCEND", "$$PRUNE"]}}); a3 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 3]}, "$$DESCEND", "$$PRUNE"]}}); a4 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 4]}, "$$DESCEND", "$$PRUNE"]}}); a5 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 5]}, "$$DESCEND", "$$PRUNE"]}}); a1result = [{_id: 1, level: 1, l: {}, o: [], q: 14}]; a2result = [{ _id: 1, level: 1, h: { level: 2, }, l: {}, o: [], q: 14 }]; a3result = [{ _id: 1, level: 1, b: { level: 3, c: 5, d: [{level: 1, e: 4}, {f: 6}, "NOT AN OBJECT!!11!", [2, 3, 4, {level: 1, r: 11}]] }, h: { level: 2, }, l: {m: {level: 3, n: 12}}, o: [], q: 14 }]; a4result = [ { _id: 1, level: 1, b: { level: 3, c: 5, d: [{level: 1, e: 4}, {f: 6}, "NOT AN OBJECT!!11!", [2, 3, 4, {level: 1, r: 11}]] }, h: {level: 2, i: {level: 4, j: {level: 1, k: 8}}}, l: {m: {level: 3, n: 12}}, o: [], q: 14 }, { _id: 2, level: 4, } ]; a5result = [ { _id: 1, level: 1, b: { level: 3, c: 5, d: [ {level: 1, e: 4}, {f: 6}, {level: 5, g: 9}, "NOT AN OBJECT!!11!", [2, 3, 4, {level: 1, r: 11}, {level: 5, s: 99}] ] }, h: {level: 2, i: {level: 4, j: {level: 1, k: 8}}}, l: {m: {level: 3, n: 12}}, o: [{level: 5, p: 19}], q: 14 }, { _id: 2, level: 4, } ]; assert.eq(a1.toArray(), a1result); assert.eq(a2.toArray(), a2result); assert.eq(a3.toArray(), a3result); assert.eq(a4.toArray(), a4result); assert.eq(a5.toArray(), a5result); // Test redacts that are just a variable access (this can happen as a result of optimizations) assert.eq(t.aggregate({$redact: "$$PRUNE"}).toArray(), []); assert.eq(t.aggregate({$redact: "$$KEEP"}).toArray(), t.find().toArray()); assert.eq(t.aggregate({$redact: "$$DESCEND"}).toArray(), t.find().toArray()); // test $$KEEP t.drop(); // entire document should be present at 2 and beyond t.save({_id: 1, level: 2, b: {level: 3, c: 2}, d: {level: 1, e: 8}, f: 9}); b1 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 1]}, "$$KEEP", "$$PRUNE"]}}); b2 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 2]}, "$$KEEP", "$$PRUNE"]}}); b3 = t.aggregate({$redact: {$cond: [{$lte: ['$level', 3]}, "$$KEEP", "$$PRUNE"]}}); b1result = []; b23result = [{_id: 1, level: 2, b: {level: 3, c: 2}, d: {level: 1, e: 8}, f: 9}]; assert.eq(b1.toArray(), b1result); assert.eq(b2.toArray(), b23result); assert.eq(b3.toArray(), b23result);