// Cannot implicitly shard accessed collections because of following errmsg: A single // update/delete on a sharded collection must contain an exact match on _id or contain the shard // key. // @tags: [ // assumes_unsharded_collection, // ] /** * Test that projection with a positional operator works with findAndModify * when remove=true or new=false, but not when new=true. */ (function() { 'use strict'; var collName = 'find_and_modify_server6865'; var t = db.getCollection(collName); t.drop(); /** * Asserts that the specified query and projection returns the expected * result, using both the find() operation and the findAndModify command. * * insert -- document to insert after dropping collection t * cmdObj -- arguments to the findAndModify command * * expected -- the document 'value' expected to be returned after the * projection is applied */ function testFAMWorked(insert, cmdObj, expected) { t.drop(); t.insert(insert); var res; if (!cmdObj['new']) { // Test that the find operation returns the expected result. res = t.findOne(cmdObj['query'], cmdObj['fields']); assert.eq(res, expected, 'positional projection failed for find'); } // Test that the findAndModify command returns the expected result. res = t.runCommand('findAndModify', cmdObj); assert.commandWorked(res, 'findAndModify command failed'); assert.eq(res.value, expected, 'positional projection failed for findAndModify'); if (cmdObj['new']) { // Test that the find operation returns the expected result. res = t.findOne(cmdObj['query'], cmdObj['fields']); assert.eq(res, expected, 'positional projection failed for find'); } } /** * Asserts that the specified findAndModify command returns an error. */ function testFAMFailed(insert, cmdObj) { t.drop(); t.insert(insert); var res = t.runCommand('findAndModify', cmdObj); assert.commandFailed(res, 'findAndModify command unexpectedly succeeded'); } // // Delete operations // // Simple query that uses an inclusion projection. testFAMWorked( {_id: 42, a: [1, 2], b: 3}, {query: {_id: 42}, fields: {_id: 0, b: 1}, remove: true}, {b: 3}); // Simple query that uses an exclusion projection. testFAMWorked({_id: 42, a: [1, 2], b: 3, c: 4}, {query: {_id: 42}, fields: {a: 0, b: 0}, remove: true}, {_id: 42, c: 4}); // Simple query that uses $elemMatch in the projection. testFAMWorked({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, {query: {_id: 42}, fields: {b: {$elemMatch: {value: 2}}}, remove: true}, {_id: 42, b: [{name: 'second', value: 2}]}); // Query on an array of values while using a positional projection. testFAMWorked( {_id: 42, a: [1, 2]}, {query: {a: 2}, fields: {'a.$': 1}, remove: true}, {_id: 42, a: [2]}); // Query on an array of objects while using a positional projection. testFAMWorked({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, {query: {_id: 42, 'b.name': 'third'}, fields: {'b.$': 1}, remove: true}, {_id: 42, b: [{name: 'third', value: 3}]}); // Query on an array of objects while using a positional projection. testFAMWorked({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, {query: {_id: 42, 'b.name': 'third'}, fields: {'b.$': 1}, remove: true}, {_id: 42, b: [{name: 'third', value: 3}]}); // Query on an array of objects using $elemMatch while using an inclusion projection. testFAMWorked({ _id: 42, a: 5, b: [{name: 'john', value: 1}, {name: 'jess', value: 2}, {name: 'jeff', value: 3}] }, { query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}}, fields: {_id: 0, a: 5}, remove: true }, {a: 5}); // Query on an array of objects using $elemMatch while using the positional // operator in the projection. testFAMWorked( {_id: 42, b: [{name: 'john', value: 1}, {name: 'jess', value: 2}, {name: 'jeff', value: 3}]}, { query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}}, fields: {_id: 0, 'b.$': 1}, remove: true }, {b: [{name: 'john', value: 1}]}); // // Update operations with new=false // // Simple query that uses an inclusion projection. testFAMWorked({_id: 42, a: [1, 2], b: 3}, {query: {_id: 42}, fields: {_id: 0, b: 1}, update: {$inc: {b: 1}}, new: false}, {b: 3}); // Simple query that uses an exclusion projection. testFAMWorked({_id: 42, a: [1, 2], b: 3, c: 4}, {query: {_id: 42}, fields: {a: 0, b: 0}, update: {$set: {c: 5}}, new: false}, {_id: 42, c: 4}); // Simple query that uses $elemMatch in the projection. testFAMWorked({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, { query: {_id: 42}, fields: {b: {$elemMatch: {value: 2}}}, update: {$set: {name: '2nd'}}, new: false }, {_id: 42, b: [{name: 'second', value: 2}]}); // Query on an array of values while using a positional projection. testFAMWorked({_id: 42, a: [1, 2]}, {query: {a: 2}, fields: {'a.$': 1}, update: {$set: {'b.kind': 'xyz'}}, new: false}, {_id: 42, a: [2]}); // Query on an array of objects while using a positional projection. testFAMWorked({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, { query: {_id: 42, 'b.name': 'third'}, fields: {'b.$': 1}, update: {$set: {'b.$.kind': 'xyz'}}, new: false }, {_id: 42, b: [{name: 'third', value: 3}]}); // Query on an array of objects while using $elemMatch in the projection, // where the matched array element is modified. testFAMWorked( {_id: 1, a: [{x: 1, y: 1}, {x: 1, y: 2}]}, {query: {_id: 1}, fields: {a: {$elemMatch: {x: 1}}}, update: {$pop: {a: -1}}, new: false}, {_id: 1, a: [{x: 1, y: 1}]}); // Query on an array of objects using $elemMatch while using an inclusion projection. testFAMWorked({ _id: 42, a: 5, b: [{name: 'john', value: 1}, {name: 'jess', value: 2}, {name: 'jeff', value: 3}] }, { query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}}, fields: {_id: 0, a: 5}, update: {$inc: {a: 6}}, new: false }, {a: 5}); // Query on an array of objects using $elemMatch while using the positional // operator in the projection. testFAMWorked( {_id: 42, b: [{name: 'john', value: 1}, {name: 'jess', value: 2}, {name: 'jeff', value: 3}]}, { query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}}, fields: {_id: 0, 'b.$': 1}, update: {$set: {name: 'james'}}, new: false }, {b: [{name: 'john', value: 1}]}); // // Update operations with new=true // // Simple query that uses an inclusion projection. testFAMWorked({_id: 42, a: [1, 2], b: 3}, {query: {_id: 42}, fields: {_id: 0, b: 1}, update: {$inc: {b: 1}}, new: true}, {b: 4}); // Simple query that uses an exclusion projection. testFAMWorked({_id: 42, a: [1, 2], b: 3, c: 4}, {query: {_id: 42}, fields: {a: 0, b: 0}, update: {$set: {c: 5}}, new: true}, {_id: 42, c: 5}); // Simple query that uses $elemMatch in the projection. testFAMWorked({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, { query: {_id: 42}, fields: {b: {$elemMatch: {value: 2}}}, update: {$set: {'b.1.name': '2nd'}}, new: true }, {_id: 42, b: [{name: '2nd', value: 2}]}); // Query on an array of values while using a positional projection. testFAMFailed({_id: 42, a: [1, 2]}, {query: {a: 2}, fields: {'a.$': 1}, update: {$set: {'b.kind': 'xyz'}}, new: true}); // Query on an array of objects while using a positional projection. testFAMFailed({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, { query: {_id: 42, 'b.name': 'third'}, fields: {'b.$': 1}, update: {$set: {'b.$.kind': 'xyz'}}, new: true }); // Query on an array of objects while using $elemMatch in the projection. testFAMWorked({ _id: 42, b: [{name: 'first', value: 1}, {name: 'second', value: 2}, {name: 'third', value: 3}] }, { query: {_id: 42}, fields: {b: {$elemMatch: {value: 2}}, c: 1}, update: {$set: {c: 'xyz'}}, new: true }, {_id: 42, c: 'xyz', b: [{name: 'second', value: 2}]}); // Query on an array of objects while using $elemMatch in the projection, // where the matched array element is modified. testFAMWorked( {_id: 1, a: [{x: 1, y: 1}, {x: 1, y: 2}]}, {query: {_id: 1}, fields: {a: {$elemMatch: {x: 1}}}, update: {$pop: {a: -1}}, new: true}, {_id: 1, a: [{x: 1, y: 2}]}); // Query on an array of objects using $elemMatch while using an inclusion projection. testFAMWorked({ _id: 42, a: 5, b: [{name: 'john', value: 1}, {name: 'jess', value: 2}, {name: 'jeff', value: 3}] }, { query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}}, fields: {_id: 0, a: 5}, update: {$inc: {a: 6}}, new: true }, {a: 11}); // Query on an array of objects using $elemMatch while using the positional // operator in the projection. testFAMFailed( {_id: 42, b: [{name: 'john', value: 1}, {name: 'jess', value: 2}, {name: 'jeff', value: 3}]}, { query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}}, fields: {_id: 0, 'b.$': 1}, update: {$set: {name: 'james'}}, new: true }); })();